[
  {
    "path": ".gitattributes",
    "content": "# Auto detect text files and perform LF normalization\n* text=auto\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore\n\n# User-specific files\n*.rsuser\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n*.env\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Mono auto generated files\nmono_crash.*\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\n\n[Dd]ebug/x64/\n[Dd]ebugPublic/x64/\n[Rr]elease/x64/\n[Rr]eleases/x64/\nbin/x64/\nobj/x64/\n\n[Dd]ebug/x86/\n[Dd]ebugPublic/x86/\n[Rr]elease/x86/\n[Rr]eleases/x86/\nbin/x86/\nobj/x86/\n\n[Ww][Ii][Nn]32/\n[Aa][Rr][Mm]/\n[Aa][Rr][Mm]64/\n[Aa][Rr][Mm]64[Ee][Cc]/\nbld/\n[Oo]bj/\n[Oo]ut/\n[Ll]og/\n[Ll]ogs/\n\n# Build results on 'Bin' directories\n**/[Bb]in/*\n# Uncomment if you have tasks that rely on *.refresh files to move binaries\n# (https://github.com/github/gitignore/pull/3736)\n#!**/[Bb]in/*.refresh\n\n# Visual Studio 2015/2017 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# Visual Studio 2017 auto generated files\nGenerated\\ Files/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n*.trx\n\n# NUnit\n*.VisualState.xml\nTestResult.xml\nnunit-*.xml\n\n# Approval Tests result files\n*.received.*\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# Benchmark Results\nBenchmarkDotNet.Artifacts/\n\n# .NET Core\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n\n# ASP.NET Scaffolding\nScaffoldingReadMe.txt\n\n# StyleCop\nStyleCopReport.xml\n\n# Files built by Visual Studio\n*_i.c\n*_p.c\n*_h.h\n*.ilk\n*.meta\n*.obj\n*.idb\n*.iobj\n*.pch\n*.pdb\n*.ipdb\n*.pgc\n*.pgd\n*.rsp\n# but not Directory.Build.rsp, as it configures directory-level build defaults\n!Directory.Build.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*_wpftmp.csproj\n*.log\n*.tlog\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# Visual Studio Trace Files\n*.e2e\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# AxoCover is a Code Coverage Tool\n.axoCover/*\n!.axoCover/settings.json\n\n# Coverlet is a free, cross platform Code Coverage Tool\ncoverage*.json\ncoverage*.xml\ncoverage*.info\n\n# Visual Studio code coverage results\n*.coverage\n*.coveragexml\n\n# NCrunch\n_NCrunch_*\n.NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# Note: Comment the next line if you want to checkin your web deploy settings,\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# NuGet Symbol Packages\n*.snupkg\n# The packages folder can be ignored because of Package Restore\n**/[Pp]ackages/*\n# except build/, which is used as an MSBuild target.\n!**/[Pp]ackages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/[Pp]ackages/repositories.config\n# NuGet v3's project.json files produces more ignorable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n*.appx\n*.appxbundle\n*.appxupload\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!?*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\norleans.codegen.cs\n\n# Including strong name files can present a security risk\n# (https://github.com/github/gitignore/pull/2483#issue-259490424)\n#*.snk\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\nServiceFabricBackup/\n*.rptproj.bak\n\n# SQL Server files\n*.mdf\n*.ldf\n*.ndf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n*.rptproj.rsuser\n*- [Bb]ackup.rdl\n*- [Bb]ackup ([0-9]).rdl\n*- [Bb]ackup ([0-9][0-9]).rdl\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\nnode_modules/\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)\n*.vbw\n\n# Visual Studio 6 workspace and project file (working project files containing files to include in project)\n*.dsw\n*.dsp\n\n# Visual Studio 6 technical files\n*.ncb\n*.aps\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n**/.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n**/.fake/\n\n# CodeRush personal settings\n**/.cr/personal\n\n# Python Tools for Visual Studio (PTVS)\n**/__pycache__/\n*.pyc\n\n# Cake - Uncomment if you are using it\n#tools/**\n#!tools/packages.config\n\n# Tabs Studio\n*.tss\n\n# Telerik's JustMock configuration file\n*.jmconfig\n\n# BizTalk build output\n*.btp.cs\n*.btm.cs\n*.odx.cs\n*.xsd.cs\n\n# OpenCover UI analysis results\nOpenCover/\n\n# Azure Stream Analytics local run output\nASALocalRun/\n\n# MSBuild Binary and Structured Log\n*.binlog\nMSBuild_Logs/\n\n# AWS SAM Build and Temporary Artifacts folder\n.aws-sam\n\n# NVidia Nsight GPU debugger configuration file\n*.nvuser\n\n# MFractors (Xamarin productivity tool) working folder\n**/.mfractor/\n\n# Local History for Visual Studio\n**/.localhistory/\n\n# Visual Studio History (VSHistory) files\n.vshistory/\n\n# BeatPulse healthcheck temp database\nhealthchecksdb\n\n# Backup folder for Package Reference Convert tool in Visual Studio 2017\nMigrationBackup/\n\n# Ionide (cross platform F# VS Code tools) working folder\n**/.ionide/\n\n# Fody - auto-generated XML schema\nFodyWeavers.xsd\n\n# VS Code files for those working on multiple tools\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n!.vscode/*.code-snippets\n\n# Local History for Visual Studio Code\n.history/\n\n# Built Visual Studio Code Extensions\n*.vsix\n\n# Windows Installer files from build outputs\n*.cab\n*.msi\n*.msix\n*.msm\n*.msp\n\n*.nes\n*.fm3\n*.fm2\n*.fmv\n*.3ct\n*.bk2\nbin/Debug/TriCNES.exe\nbin/Debug/TriCNES.exe.config\nbin/Debug/TriCNES.pdb\nbin/Release/TriCNES.exe\nbin/Release/TriCNES.exe.config\nbin/Release/TriCNES.pdb\n.vs/TriCNES/FileContentIndex/a1f39354-40ca-44d4-a1f4-22570f4e355b.vsidx\n.vs/TriCNES/FileContentIndex/4bef6b04-ae46-46c1-a5d2-a4ddde2871fe.vsidx\n*.vsidx\n*.vsidx\n*.cache\n/obj\n*.vsidx\n*.vsidx\n*.tasproj\n/bin/Release/roms\n/bin\n"
  },
  {
    "path": "6502Documentation.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace TriCNES\n{\n    public class Op\n    {\n        public byte code;\n        public string mnemonic;\n        public string mode;\n        public int length;\n        public int affectedFlags;\n        public string CycleByCycle;\n        public string InstructionDocumentation;\n\n        public Op(byte c, string m, string mo, int l, int a, string d, string i)\n        {\n            code = c;\n            mnemonic = m;\n            mode = mo;\n            length = l;\n            affectedFlags = a;\n            CycleByCycle = d;\n            InstructionDocumentation = i;\n        }\n\n\n    }\n\n\n\n    public static class Documentation\n    {\n\n        // This class is exlusively referenced for debugging and trace logging information.\n        // It's also possible I mistyped some numbers here and there, and probably shouldn't be 100% trusted.\n\n\n\n        //cycle information from https://www.atarihq.com/danb/files/64doc.txt\n\n        static int cFlag = 1;\n        static int zFlag = 2;\n        static int iFlag = 4;\n        static int dFlag = 8;\n\n\n        static int vFlag = 64;\n        static int nFlag = 128;\n        static int aChanges = 256;\n        static int xChanges = 512;\n        static int yChanges = 1024;\n        static int stackPChanges = 2048;\n        static int pcChanges = 4096;\n        static int memChanges = 8192;\n\n\n        static string[] CycleDocs =\n        {\n            //0 BRK\n            \"        #  address R/W description\\r\\n       --- ------- --- -----------------------------------------------\\r\\n        1    PC     R  fetch opcode, increment PC\\r\\n        2    PC     R  read next instruction byte (and throw it away), increment PC\\r\\n        3  $0100,S  W  push PCH on stack, decrement S\\r\\n        4  $0100,S  W  push PCL on stack, decrement S\\r\\n        5  $0100,S  W  push P on stack (with B flag set), decrement S\\r\\n        6   $FFFE   R  fetch PCL\\r\\n        7   $FFFF   R  fetch PCH\"\n            ,\n            //1 RTI\n            \"        #  address R/W description\\r\\n       --- ------- --- -----------------------------------------------\\r\\n        1    PC     R  fetch opcode, increment PC\\r\\n        2    PC     R  read next instruction byte (and throw it away)\\r\\n        3  $0100,S  R  increment S\\r\\n        4  $0100,S  R  pull P from stack, increment S\\r\\n        5  $0100,S  R  pull PCL from stack, increment S\\r\\n        6  $0100,S  R  pull PCH from stack\"\n            ,\n            //2 RTS\n            \"        #  address R/W description\\r\\n       --- ------- --- -----------------------------------------------\\r\\n        1    PC     R  fetch opcode, increment PC\\r\\n        2    PC     R  read next instruction byte (and throw it away)\\r\\n        3  $0100,S  R  increment S\\r\\n        4  $0100,S  R  pull PCL from stack, increment S\\r\\n        5  $0100,S  R  pull PCH from stack\\r\\n        6    PC     R  increment PC\"\n            ,\n            //3 PHA, PHP\n            \"        #  address R/W description\\r\\n       --- ------- --- -----------------------------------------------\\r\\n        1    PC     R  fetch opcode, increment PC\\r\\n        2    PC     R  read next instruction byte (and throw it away)\\r\\n        3  $0100,S  W  push register on stack, decrement S\"\n            ,\n            //4 PLA, PLP\n            \"        #  address R/W description\\r\\n       --- ------- --- -----------------------------------------------\\r\\n        1    PC     R  fetch opcode, increment PC\\r\\n        2    PC     R  read next instruction byte (and throw it away)\\r\\n        3  $0100,S  R  increment S\\r\\n        4  $0100,S  R  pull register from stack\"\n            ,\n            //5 JSR\n            \"        #  address R/W description\\r\\n       --- ------- --- -------------------------------------------------\\r\\n        1    PC     R  fetch opcode, increment PC\\r\\n        2    PC     R  fetch low address byte, increment PC\\r\\n        3  $0100,S  R  internal operation (predecrement S?)\\r\\n        4  $0100,S  W  push PCH on stack, decrement S\\r\\n        5  $0100,S  W  push PCL on stack, decrement S\\r\\n        6    PC     R  copy low address byte to PCL, fetch high address byte to PCH\"\n            ,\n            //6 Accumulator or implied addressing\n            \"  Accumulator or implied addressing\\r\\n\\r\\n        #  address R/W description\\r\\n       --- ------- --- -----------------------------------------------\\r\\n        1    PC     R  fetch opcode, increment PC\\r\\n        2    PC     R  read next instruction byte (and throw it away)\"\n            ,\n            //7 Immediate addressing\n            \"        #  address R/W description\\r\\n       --- ------- --- ------------------------------------------\\r\\n        1    PC     R  fetch opcode, increment PC\\r\\n        2    PC     R  fetch value, increment PC\"\n            ,\n            // --Absolute Instructions--\n            //8 JMP\n            \"        #  address R/W description\\r\\n       --- ------- --- -------------------------------------------------\\r\\n        1    PC     R  fetch opcode, increment PC\\r\\n        2    PC     R  fetch low address byte, increment PC\\r\\n        3    PC     R  copy low address byte to PCL, fetch high address byte to PCH\"\n            ,\n            //9 Read instructions (LDA, LDX, LDY, EOR, AND, ORA, ADC, SBC, CMP, BIT, LAX, NOP)\n            \"        #  address R/W description\\r\\n       --- ------- --- ------------------------------------------\\r\\n        1    PC     R  fetch opcode, increment PC\\r\\n        2    PC     R  fetch low byte of address, increment PC\\r\\n        3    PC     R  fetch high byte of address, increment PC\\r\\n        4  address  R  read from effective address\"\n            ,\n            //10 Read-Modify-Write instructions (ASL, LSR, ROL, ROR, INC, DEC, SLO, SRE, RLA, RRA, ISC, DCP)\n            \"        #  address R/W description\\r\\n       --- ------- --- ------------------------------------------\\r\\n        1    PC     R  fetch opcode, increment PC\\r\\n        2    PC     R  fetch low byte of address, increment PC\\r\\n        3    PC     R  fetch high byte of address, increment PC\\r\\n        4  address  R  read from effective address\\r\\n        5  address  W  write the value back to effective address, and do the operation on it\\r\\n        6  address  W  write the new value to effective address\"\n            ,\n            //11 Write instructions (STA, STX, STY, SAX)\n            \"        #  address R/W description\\r\\n       --- ------- --- ------------------------------------------\\r\\n        1    PC     R  fetch opcode, increment PC\\r\\n        2    PC     R  fetch low byte of address, increment PC\\r\\n        3    PC     R  fetch high byte of address, increment PC\\r\\n        4  address  W  write register to effective address\"\n            ,\n            // --Zero page addressing--\n            //12 Read instructions (LDA, LDX, LDY, EOR, AND, ORA, ADC, SBC, CMP, BIT, LAX, NOP)\n            \"        #  address R/W description\\r\\n       --- ------- --- ------------------------------------------\\r\\n        1    PC     R  fetch opcode, increment PC\\r\\n        2    PC     R  fetch address, increment PC\\r\\n        3  address  R  read from effective address\"\n            ,\n            //13 Read-Modify-Write instructions (ASL, LSR, ROL, ROR, INC, DEC, SLO, SRE, RLA, RRA, ISC, DCP)\n            \"        #  address R/W description\\r\\n       --- ------- --- ------------------------------------------\\r\\n        1    PC     R  fetch opcode, increment PC\\r\\n        2    PC     R  fetch address, increment PC\\r\\n        3  address  R  read from effective address\\r\\n        4  address  W  write the value back to effective address, and do the operation on it\\r\\n        5  address  W  write the new value to effective address\"\n            ,\n            //14 Write instructions (STA, STX, STY, SAX)\n            \"        #  address R/W description\\r\\n       --- ------- --- ------------------------------------------\\r\\n        1    PC     R  fetch opcode, increment PC\\r\\n        2    PC     R  fetch address, increment PC\\r\\n        3  address  W  write register to effective address\"\n            ,\n            // --Zero page indexed addressing--\n            //15 Read instructions (LDA, LDX, LDY, EOR, AND, ORA, ADC, SBC, CMP, BIT, LAX, NOP)\n            \"        #   address  R/W description\\r\\n       --- --------- --- ------------------------------------------\\r\\n        1     PC      R  fetch opcode, increment PC\\r\\n        2     PC      R  fetch address, increment PC\\r\\n        3   address   R  read from address, add index register to it\\r\\n        4  address+I* R  read from effective address\\r\\n\\r\\n       Notes: I denotes either index register (X or Y).\\r\\n\\r\\n              * The high byte of the effective address is always zero,\\r\\n                i.e. page boundary crossings are not handled.\"\n            ,\n            //16 Read-Modify-Write instructions (ASL, LSR, ROL, ROR, INC, DEC, SLO, SRE, RLA, RRA, ISC, DCP)\n            \"        #   address  R/W description\\r\\n       --- --------- --- ---------------------------------------------\\r\\n        1     PC      R  fetch opcode, increment PC\\r\\n        2     PC      R  fetch address, increment PC\\r\\n        3   address   R  read from address, add index register X to it\\r\\n        4  address+X* R  read from effective address\\r\\n        5  address+X* W  write the value back to effective address, and do the operation on it\\r\\n        6  address+X* W  write the new value to effective address\\r\\n\\r\\n       Note: * The high byte of the effective address is always zero,\\r\\n               i.e. page boundary crossings are not handled.\"\n            ,\n            //17 Write instructions (STA, STX, STY, SAX)\n            \"        #   address  R/W description\\r\\n       --- --------- --- -------------------------------------------\\r\\n        1     PC      R  fetch opcode, increment PC\\r\\n        2     PC      R  fetch address, increment PC\\r\\n        3   address   R  read from address, add index register to it\\r\\n        4  address+I* W  write to effective address\\r\\n\\r\\n       Notes: I denotes either index register (X or Y).\\r\\n\\r\\n              * The high byte of the effective address is always zero,\\r\\n                i.e. page boundary crossings are not handled.\"\n            ,\n            // --Absolute indexed addressing--\n            //18 Read instructions (LDA, LDX, LDY, EOR, AND, ORA, ADC, SBC, CMP, BIT, LAX, LAE, SHS, NOP)\n            \"        #   address  R/W description\\r\\n       --- --------- --- ------------------------------------------\\r\\n        1     PC      R  fetch opcode, increment PC\\r\\n        2     PC      R  fetch low byte of address, increment PC\\r\\n        3     PC      R  fetch high byte of address, add index register to low address byte, increment PC\\r\\n        4  address+I* R  read from effective address, fix the high byte of effective address\\r\\n        5+ address+I  R  re-read from effective address\\r\\n\\r\\n       Notes: I denotes either index register (X or Y).\\r\\n\\r\\n              * The high byte of the effective address may be invalid\\r\\n                at this time, i.e. it may be smaller by $100.\\r\\n\\r\\n              + This cycle will be executed only if the effective address\\r\\n                was invalid during cycle #4, i.e. page boundary was crossed.\"\n            ,\n            //19 Read-Modify-Write instructions (ASL, LSR, ROL, ROR, INC, DEC, SLO, SRE, RLA, RRA, ISC, DCP)\n            \"        #   address  R/W description\\r\\n       --- --------- --- ------------------------------------------\\r\\n        1    PC       R  fetch opcode, increment PC\\r\\n        2    PC       R  fetch low byte of address, increment PC\\r\\n        3    PC       R  fetch high byte of address, add index register X to low address byte, increment PC\\r\\n        4  address+X* R  read from effective address, fix the high byte of effective address\\r\\n        5  address+X  R  re-read from effective address\\r\\n        6  address+X  W  write the value back to effective address, and do the operation on it\\r\\n        7  address+X  W  write the new value to effective address\\r\\n\\r\\n       Notes: * The high byte of the effective address may be invalid\\r\\n                at this time, i.e. it may be smaller by $100.\"\n            ,\n            //20 Write instructions (STA, STX, STY, SHA, SHX, SHY)\n            \"        #   address  R/W description\\r\\n       --- --------- --- ------------------------------------------\\r\\n        1     PC      R  fetch opcode, increment PC\\r\\n        2     PC      R  fetch low byte of address, increment PC\\r\\n        3     PC      R  fetch high byte of address, add index register to low address byte, increment PC\\r\\n        4  address+I* R  read from effective address, fix the high byte of effective address\\r\\n        5  address+I  W  write to effective address\\r\\n\\r\\n       Notes: I denotes either index register (X or Y).\\r\\n\\r\\n              * The high byte of the effective address may be invalid\\r\\n                at this time, i.e. it may be smaller by $100. Because\\r\\n                the processor cannot undo a write to an invalid\\r\\n                address, it always reads from the address first.\"\n            ,\n            //21 Relative addressing (BCC, BCS, BNE, BEQ, BPL, BMI, BVC, BVS)\n            \"        #   address  R/W description\\r\\n       --- --------- --- ---------------------------------------------\\r\\n        1     PC      R  fetch opcode, increment PC\\r\\n        2     PC      R  fetch operand, increment PC. If branch is not taken, the instruction has ended.\\r\\n        3+    PC      R  If branch is taken, add operand to PCL.\\r\\n        4!    PC*     R  Fix PCH.\\r\\n        Notes: * The high byte of Program Counter (PCH) may be invalid\\r\\n                at this time, i.e. it may be smaller or bigger by $100.\\r\\n\\r\\n              + If branch is taken, this cycle will be executed.\\r\\n\\r\\n              ! If branch occurs to different page, this cycle will be\\r\\n                executed.\"\n            ,\n            // --Indexed indirect addressing--\n            //22 Read instructions (LDA, ORA, EOR, AND, ADC, CMP, SBC, LAX)\n            \"        #    address   R/W description\\r\\n       --- ----------- --- ------------------------------------------\\r\\n        1      PC       R  fetch opcode, increment PC\\r\\n        2      PC       R  fetch pointer address, increment PC\\r\\n        3    pointer    R  read from the address, add X to it\\r\\n        4   pointer+X   R  fetch effective address low\\r\\n        5  pointer+X+1  R  fetch effective address high\\r\\n        6    address    R  read from effective address\\r\\n\\r\\n       Note: The effective address is always fetched from zero page,\\r\\n             i.e. the zero page boundary crossing is not handled.\"\n            ,\n            //23 Read-Modify-Write instructions (SLO, SRE, RLA, RRA, ISC, DCP)\n            \"        #    address   R/W description\\r\\n       --- ----------- --- ------------------------------------------\\r\\n        1      PC       R  fetch opcode, increment PC\\r\\n        2      PC       R  fetch pointer address, increment PC\\r\\n        3    pointer    R  read from the address, add X to it\\r\\n        4   pointer+X   R  fetch effective address low\\r\\n        5  pointer+X+1  R  fetch effective address high\\r\\n        6    address    R  read from effective address\\r\\n        7    address    W  write the value back to effective address, and do the operation on it\\r\\n        8    address    W  write the new value to effective address\\r\\n\\r\\n       Note: The effective address is always fetched from zero page,\\r\\n             i.e. the zero page boundary crossing is not handled.\"\n            ,\n            //24 Write instructions (STA, SAX)\n            \"        #    address   R/W description\\r\\n       --- ----------- --- ------------------------------------------\\r\\n        1      PC       R  fetch opcode, increment PC\\r\\n        2      PC       R  fetch pointer address, increment PC\\r\\n        3    pointer    R  read from the address, add X to it\\r\\n        4   pointer+X   R  fetch effective address low\\r\\n        5  pointer+X+1  R  fetch effective address high\\r\\n        6    address    W  write to effective address\\r\\n\\r\\n       Note: The effective address is always fetched from zero page,\\r\\n             i.e. the zero page boundary crossing is not handled.\"\n            ,\n            // --Indirect indexed addressing--\n            //25 Read instructions (LDA, EOR, AND, ORA, ADC, SBC, CMP)\n            \"        #    address   R/W description\\r\\n       --- ----------- --- ------------------------------------------\\r\\n        1      PC       R  fetch opcode, increment PC\\r\\n        2      PC       R  fetch pointer address, increment PC\\r\\n        3    pointer    R  fetch effective address low\\r\\n        4   pointer+1   R  fetch effective address high, add Y to low byte of effective address\\r\\n        5   address+Y*  R  read from effective address, fix high byte of effective address\\r\\n        6+  address+Y   R  read from effective address\\r\\n\\r\\n       Notes: The effective address is always fetched from zero page,\\r\\n              i.e. the zero page boundary crossing is not handled.\\r\\n\\r\\n              * The high byte of the effective address may be invalid\\r\\n                at this time, i.e. it may be smaller by $100.\\r\\n\\r\\n              + This cycle will be executed only if the effective address\\r\\n                was invalid during cycle #5, i.e. page boundary was crossed.\"\n            ,\n            //26 Read-Modify-Write instructions (SLO, SRE, RLA, RRA, ISC, DCP)\n            \"        #    address   R/W description\\r\\n       --- ----------- --- ------------------------------------------\\r\\n        1      PC       R  fetch opcode, increment PC\\r\\n        2      PC       R  fetch pointer address, increment PC\\r\\n        3    pointer    R  fetch effective address low\\r\\n        4   pointer+1   R  fetch effective address high, add Y to low byte of effective address\\r\\n        5   address+Y*  R  read from effective address, fix high byte of effective address\\r\\n        6   address+Y   R  read from effective address\\r\\n        7   address+Y   W  write the value back to effective address, and do the operation on it\\r\\n        8   address+Y   W  write the new value to effective address\\r\\n\\r\\n       Notes: The effective address is always fetched from zero page,\\r\\n              i.e. the zero page boundary crossing is not handled.\\r\\n\\r\\n              * The high byte of the effective address may be invalid\\r\\n                at this time, i.e. it may be smaller by $100.\"\n            ,\n            //27 Write instructions (STA, SHA)\n            \"        #    address   R/W description\\r\\n       --- ----------- --- ------------------------------------------\\r\\n        1      PC       R  fetch opcode, increment PC\\r\\n        2      PC       R  fetch pointer address, increment PC\\r\\n        3    pointer    R  fetch effective address low\\r\\n        4   pointer+1   R  fetch effective address high, add Y to low byte of effective address\\r\\n        5   address+Y*  R  read from effective address, fix high byte of effective address\\r\\n        6   address+Y   W  write to effective address\\r\\n\\r\\n       Notes: The effective address is always fetched from zero page,\\r\\n              i.e. the zero page boundary crossing is not handled.\\r\\n\\r\\n              * The high byte of the effective address may be invalid\\r\\n                at this time, i.e. it may be smaller by $100.\"\n            ,\n            // --Absolute indirect addressing--\n            //28 JMP\n            \"        #   address  R/W description\\r\\n       --- --------- --- ------------------------------------------\\r\\n        1     PC      R  fetch opcode, increment PC\\r\\n        2     PC      R  fetch pointer address low, increment PC\\r\\n        3     PC      R  fetch pointer address high, increment PC\\r\\n        4   pointer   R  fetch low address to latch\\r\\n        5  pointer+1* R  fetch PCH, copy latch to PCL\\r\\n\\r\\n       Note: * The PCH will always be fetched from the same page\\r\\n               than PCL, i.e. page boundary crossing is not handled.\\r\\n\\r\\n                How Real Programmers Acknowledge Interrupts\"\n            ,\n            //29\n            //HLT\n            \"        #   address  R/W description\\r\\n       --- --------- --- ------------------------------------------\\r\\n        1     PC      R  fetch opcode, does not increment PC\\r\\n        2     PC      R  fetch opcode, does not increment PC\\r\\n        3     PC      R  fetch opcode, does not increment PC\\r\\n        4     PC      R  fetch opcode, does not increment PC\\r\\n        5     PC      R  fetch opcode, does not increment PC\\r\\n        6     PC      R  fetch opcode, does not increment PC\\r\\n        7     PC      R  fetch opcode, does not increment PC\\r\\n        ...   PC      R  fetch opcode, does not increment PC\\r\\n\\r\\n       Notes: This process goes on forever.\"\n        };\n\n        // this explains what each isntruction does by their pnuemonic\n\n        static string[] InstructionDocs =\n        {\n            //0 BRK\n            \"Break\\n\\nPushes PC to the stack.\\n\\nPushes processor status to the stack.\\nPC' = ($FFFE)\\nSP' = SP-3\"\n            ,\n            //1 ORA\n            \"Bitwise OR with Accumulator\\n\\nA' = A|M\\n\\nZFlag' = (A'==0)\\nNFlag' = (A'>=0x80)\"\n            ,\n            //2 HLT\n            \"Halt\\n\\nHalts the processor.\"\n            ,\n            //3 NOP\n            \"No operation.\"\n            ,\n            //4 ASL\n            \"Arithmetic Shift Left\\n\\nM' = M<<1\\n\\nCflag' = (M>=0x80)\\nZflag' = (M'==0)\\nNflag' = (M'>=0x80)\"\n            ,\n            //5 SLO\n            \"Arithemtic Shift Left then Bitwise OR with Accumulator\\n\\nM' = M<<1\\nA' = A|M'\\n\\nCflag' = (M>=0x80)\\nZflag' = (A'==0)\\nNflag' = (A'>=0x80)\"\n            ,\n            //6 PHP\n            \"Push Processor\\n\\nPushes processor status to the stack.\\n\\nSP' = SP-1\"\n            ,\n            //7 ANC\n            \"Bitwise AND with Accumulator then Set Carry if Negative\\n\\nA' = A & M\\n\\nCflag' = (A'>=0x80)\\nZflag' = (A'==0)\\nNflag' = (A'>=0x80)\"\n            ,\n            //8 BPL\n            \"Branch on Plus\\n\\nIf the negative flag is not set, branch.\\n\\nPC' = PC + (!NFlag ? SignedOperand : 0)\"\n            ,\n            //9 CLC\n            \"Clear Carry Flag\\n\\nCFlag' = false\"\n            ,\n            //10 JSR\n            \"Jump to Subroutine\\n\\nPushes PC to the stack\\nPC' = Operand\\nSP' = SP-2\"\n            ,\n            //11 AND\n            \"Bitwise AND with Accumulator\\n\\nA' = A&M\\n\\nZFlag = (A'==0)\\nNFlag' = (A'>=0x80)\"\n            ,\n            //12 RLA\n            \"Rotate Left then Bitwise AND with Accumulator\\n\\nM' = M<<1 + CFlag\\nA' = A&M'\\n\\nCflag' = (M>=0x80)\\nZflag' = (A'==0)\\nNflag' = (A'>=0x80)\"\n            ,\n            //13 BIT\n            \"Bit Test\\n\\nZFlag = (A=M)\\nNFlag = ((M>>7)&1==1)\\nVFlag = ((M>>6)&1==1)\"\n            ,\n            //14 ROL\n            \"Rotate Left\\n\\nM' = M<<1 + CFlag\\n\\nCflag' = (M>=0x80)\\nZflag' = (M'==0)\\nNflag' = (M'>=0x80)\"\n            ,\n            //15 PLP\n            \"Pull Processor\\n\\nPulls processor status from the stack.\\n\\nSP' = SP+1\"\n            ,\n            //16 BMI\n            \"Branch on Minus\\n\\nIf the negative flag is set, branch.\\n\\nPC' = PC + (NFlag ? SignedOperand : 0)\"\n            ,\n            //17 SEC\n            \"Set Carry Flag\\n\\nCFlag' = true\"\n            ,\n            //18 RTI\n            \"Return from Interrupt\\n\\nPulls the processor from the stack.\\nPulls PC from the stack.\\n\\nSP' = SP+3\"\n            ,\n            //19 EOR\n            \"Bitwise Exclusive OR with Accumulator\\n\\nA' = A^M\\n\\nZFlag' = (A'==0)\\nNFlag' = (A'>=0x80)\"\n            ,\n            //20 SRE\n            \"Logical Shift Right then Bitwise Exclusive OR with Accumulator\\n\\nM' = M>>2\\nA' = A^M'\\n\\nCFlag' = (M&1==1)\\nZflag' = (A'==0)\\nNflag' = (A'>=0x80)\"\n            ,\n            //21 LSR\n            \"Logical Shift Right\\n\\nM' = M>>2\\n\\nCFlag' = (M&1==1)\\nZflag' = (M'==0)\\nNflag' = (M'>=0x80)\"\n            ,\n            //22 PHA\n            \"Push A\\n\\nPushes A to the stack.\\n\\nSP' = SP-1\"\n            ,\n            //23 ASR\n            \"Bitwise AND with Accumulator then Logical Shift Right Accumulator\\n\\nA' = ((A&M)>>1)\\nCFlag' = ((A&M)&1==1)\\nZflag' = (A'==0)\\nNflag' = (A'>=0x80)\"\n            ,\n            //24 JMP\n            \"Jump\\n\\nPC' = M\"\n            ,\n            //25 BVC\n            \"Branch on Overflow Clear\\n\\nIf the overflow flag is not set, branch.\\n\\nPC' = PC + (!VFlag ? SignedOperand : 0)\"\n            ,\n            //26 CLI\n            \"Clear Interrupt Disable Flag\\n\\nIFlag' = false\"\n            ,\n            //27 RTS\n            \"Return from Subroutine\\n\\nPulls the PC from the stack.\\\\SP' = SP + 2\"\n            ,\n            //28 ADC\n            \"Add with Carry\\n\\nA' = A + M + CFlag\\n\\nVFlag' = ((A ^ (M + A + Carry)) & ((M + A + Carry) & M) & 0x80) == 0x80\\nCFlag' = A + M > 0xFF\\nZflag' = (A'==0)\\nNflag' = (A'>=0x80)\"\n            ,\n            //29 RRA\n            \"Rotate Right then Add With Carry\\n\\nM' = (M>>1)+Cflag*0x80\\n\\nVFlag' = ((A ^ (M + A + Carry)) & ((M + A + Carry) & M) & 0x80) == 0x80\\nCFlag' = A + M > 0xFF\\nZflag' = (A'==0)\\nNflag' = (A'>=0x80)\"\n            ,\n            //30 ROR\n            \"Rotate Right\\n\\nM' = M>>1 + CFlag*0x80\\n\\nCflag' = (M&1)\\nZflag' = (M'==0)\\nNflag' = (M'>=0x80)\"\n            ,\n            //31 PLA\n            \"Pull A\\n\\nPull A from the stack\\n\\nSP' = SP+1\"\n            ,\n            //32 ARR\n            \"Bitwise AND with A then Rotate A and check bits\\n\\nA' = ((A&M)>>1)+Carry*0x80\\n\\nCFlag = ((A'>>6)&1==1)\\nVFlag = ((A'>>5)&1==1)\\nZFlag' = (A'==0)\\nNFlag' = (A'>=0x80)\"\n            ,\n            //33 BVS\n            \"Branch on Overflow Set\\n\\nIf the overflow flag is set, branch.\\n\\nPC' = PC + (VFlag ? SignedOperand : 0)\"\n            ,\n            //34 SEI\n            \"Set Interrupt Disable Flag\\n\\nIFlag' = true\"\n            ,\n            //35 STA\n            \"Store A\\n\\nM' = A\"\n            ,\n            //36 SAX\n            \"Store A and X\\n\\nM' = A&X\"\n            ,\n            //37 STY\n            \"Store Y\\n\\nM' = Y\"\n            ,\n            //38 STX\n            \"Store X\\n\\nM' = X\"\n            ,\n            //39 DEY\n            \"Decrement Y\\n\\nY' = Y-1\\n\\nZFlag' = (Y'==0)\\nNFlag' = (Y'>=0x80)\"\n            ,\n            //40 TXA\n            \"Transfer X to A\\n\\nA' = X\\n\\nZFlag' = (A'==0)\\nNFlag' = (A'>=0x80)\"\n            ,\n            //41 ANE\n            \"Bitwise OR A with Magic then Bitwise AND with X AND with Memory\\n\\nA' = (A | magic) & X & M\\n\\n     *Note: 'Magic' depends on the chip manufacturer\\n            'Magic' is usually 00, EE, EF, FE, or FF\"\n            ,\n            //42 BCC\n            \"Branch on Carry Clear\\n\\nIf the carry flag is not set, branch.\\n\\nPC' = PC + (!CFlag ? SignedOperand : 0)\"\n            ,\n            //43 TXS\n            \"Transfer X to Stack Pointer\\n\\nSP' = X\"\n            ,\n            //44 SHA\n            \"Store Bitwise AND X with A AND the High Byte of the Operand Plus 1\\n\\nM' = A & X & (HIGH(Arg)+1)\"\n            ,\n            //45 TYA\n            \"Transfer Y to A\\n\\nA' = Y\\n\\nZFlag' = (A'==0)\\nNFlag' = (A'>=0x80)\"\n            ,\n            //46 SHY\n            \"Store Bitwise AND Y with The High Byte of the Operand Plus 1\\n\\nM' = Y & (HIGH(Arg)+1)\"\n            ,\n            //47 SHS\n            \"Transfer Bitwise AND A with X to Stack Pointer then Store Bitwise And Stack Pointer with the High Byte of the Operand Plus 1\\n\\nSP' = A&X\\nM' = SP'&(HIGH(Arg)+1)\"\n            ,\n            //48 SHX\n            \"Store Bitwise AND X with The High Byte of the Operand Plus 1\\n\\nM' = X & (HIGH(Arg)+1)\"\n            ,\n            //49 LDY\n            \"Load Y\\n\\nY' = M\\n\\nZFlag' = (Y'==0)\\nNFlag' = (Y'>=0x80)\"\n            ,\n            //50 LDA\n            \"Load A\\n\\nA' = M\\n\\nZFlag' = (A'==0)\\nNFlag' = (A'>=0x80)\"\n            ,\n            //51 LDX\n            \"Load X\\n\\nX' = M\\n\\nZFlag' = (X'==0)\\nNFlag' = (X'>=0x80)\"\n            ,\n            //52 LAX\n            \"Load A X\\n\\nA' = M\\nX' = M\\n\\nZFlag' = (X'==0)\\nNFlag' = (X'>=0x80)\"\n            ,\n            //53 TAY\n            \"Transfer A to Y\\n\\nY' = A\\n\\nZFlag' = (Y'==0)\\nNFlag' = (Y'>=0x80)\"\n            ,\n            //54 TAX\n            \"Transfer A to X\\n\\nX' = A\\n\\nZFlag' = (X'==0)\\nNFlag' = (X'>=0x80)\"\n            ,\n            //55 LXA\n            \"Bitwise AND with A then Transfer A to X\\n\\nA' = A&M\\nX'=A'\\n\\nZFlag' = (X'==0)\\nNFlag' = (X'>=0x80)\"\n            ,\n            //56 BCS\n            \"Branch on Carry Set\\n\\nIf the carry flag is set, branch.\\n\\nPC' = PC + (CFlag ? SignedOperand : 0)\"\n            ,\n            //57 CLV\n            \"Clear Overflow\\n\\nVFlag = false\"\n            ,\n            //58 TSX\n            \"Transfer Stack Pointer to X\\n\\nX' = SP\"\n            ,\n            //59 LAS\n            \"Transfer Bitwise AND with Stack Pointer to A, X, and Stack Pointer\\n\\nA' = M&SP\\nX' = M&SP\\nSP' = M&SP\"\n            ,\n            //60 CPY\n            \"Compare Y\\n\\nZFlag' = (Y==M)\\nCFlag' = (Y>=M)\\nNFlag' = (Y-M)>0x80\"\n            ,\n            //61 CMP\n            \"Compare A\\n\\nZFlag' = (A==M)\\nCFlag' = (A>=M)\\nNFlag' = (A-M)>0x80\"\n            ,\n            //62 DCP\n            \"Decrement then Compare A\\n\\nM' = M-1\\nZFlag' = (A==M')\\nCFlag' = (A>=M')\\nNFlag' = (A-M')>0x80\"\n            ,\n            //63 DEC\n            \"Decrement\\n\\nM' = M-1\\n\\nZFlag' = (M'==0)\\nNFlag' = (M'>=0x80)\"\n            ,\n            //64 INY\n            \"Increment Y\\n\\nY' = Y+1\\n\\nZFlag' = (Y'==0)\\nNFlag' = (Y'>=0x80)\"\n            ,\n            //65 DEX\n            \"Decrement X\\n\\nX' = X-1\\n\\nZFlag' = (X'==0)\\nNFlag' = (X'>=0x80)\"\n            ,\n            //66 AXS\n            \"Load X with Subtraction with Bitwise AND X with A\\n\\nX' = (A&X)-M\\n\\nZFlag' = (X==M)\\nCFlag' = (X>=M)\\nNFlag' = (X-M)>0x80\"\n            ,\n            //67 BNE\n            \"Branch on Not Equal\\n\\nIf the zero flag is not set, branch.\\n\\nPC' = PC + (!ZFlag ? SignedOperand : 0)\"\n            ,\n            //68 CLD\n            \"Clear Decimal Flag\\n\\nDFlag = false\"\n            ,\n            //69 CPX\n            \"Compare X\\n\\nZFlag' = (X==M)\\nCFlag' = (X>=M)\\nNFlag' = (X-M)>0x80\"\n            ,\n            //70 SBC\n            \"Subtract with Carry\\n\\nA' = A+(0xFF-M)+CFlag\\n\\nVFlag' = ((A ^ (M + A + Carry)) & ((M + A + Carry) & M) & 0x80) == 0x80\\nCFlag' = A + M > 0xFF\\nZflag' = (A'==0)\\nNflag' = (A'>=0x80)\"\n            ,\n            //71 ISC\n            \"Increment then subtract from accumulator\\n\\nM' = M+1\\nA' = A+(0xFF-M')+CFlag\\n\\nVFlag' = ((A ^ (M' + A + Carry)) & ((M' + A + Carry) & M') & 0x80) == 0x80\\nCFlag' = A + M' > 0xFF\\nZflag' = (M'==0)\\nNflag' = (M'>=0x80)\"\n            ,\n            //72 INC\n            \"Increment\\n\\nM' = M+1\\n\\nZFlag' = (A'==0)\\nNFlag' = (A'>=0x80)\"\n            ,\n            //73 INX\n            \"Increment\\n\\nX' = X+1\\n\\nZFlag' = (X'==0)\\nNFlag' = (X'>=0x80)\"\n            ,\n            //74 BEQ\n            \"Branch on Equal\\n\\nIf the zero flag is set, branch.\\n\\nPC' = PC + (ZFlag ? SignedOperand : 0)\"\n            ,\n            //75 SED\n            \"Set Decimal\\n\\nDFlag = true\"\n\n\n        };\n\n        // this table is referenced in the debugging stuff.\n        // basically, for each index into this array, you can fetch an opcode's name, addressing mode, what flags/registers it can modify, documentation, and the number of cycles before a read/write.\n\n        public static Op[] OpDocs = {\n            new Op(0x00,\"BRK\",\"i\"       ,2,stackPChanges | pcChanges            ,CycleDocs[0] ,InstructionDocs[0]),\n            new Op(0x01,\"ORA\",\"(d,x)\"   ,2,nFlag | zFlag | aChanges                     ,CycleDocs[22],InstructionDocs[1]),\n            new Op(0x02,\"HLT\",\"i\"       ,1,0                                            ,CycleDocs[29],InstructionDocs[2]),\n            new Op(0x03,\"SLO\",\"(d,x)\"   ,2,nFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[23],InstructionDocs[5]),\n            new Op(0x04,\"NOP\",\"d\"       ,2,0                                            ,CycleDocs[12],InstructionDocs[3]),\n            new Op(0x05,\"ORA\",\"d\"       ,2,nFlag | zFlag | aChanges                     ,CycleDocs[12],InstructionDocs[1]),\n            new Op(0x06,\"ASL\",\"d\"       ,2,nFlag | zFlag | cFlag | memChanges           ,CycleDocs[13],InstructionDocs[4]),\n            new Op(0x07,\"SLO\",\"d\"       ,2,nFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[13],InstructionDocs[5]),\n            new Op(0x08,\"PHP\",\"i\"       ,1,stackPChanges                                ,CycleDocs[3] ,InstructionDocs[6]),\n            new Op(0x09,\"ORA\",\"#v\"      ,2,nFlag | zFlag | aChanges                     ,CycleDocs[7] ,InstructionDocs[1]),\n            new Op(0x0A,\"ASL\",\"A\"       ,1,nFlag | zFlag | cFlag | aChanges             ,CycleDocs[6] ,InstructionDocs[4]),\n            new Op(0x0B,\"ANC\",\"#v\"      ,2,nFlag | zFlag | cFlag | aChanges             ,CycleDocs[7] ,InstructionDocs[7]),\n            new Op(0x0C,\"NOP\",\"a\"       ,3,0                                            ,CycleDocs[9] ,InstructionDocs[3]),\n            new Op(0x0D,\"ORA\",\"a\"       ,3,nFlag | zFlag | aChanges                     ,CycleDocs[9] ,InstructionDocs[1]),\n            new Op(0x0E,\"ASL\",\"a\"       ,3,nFlag | zFlag | cFlag | memChanges           ,CycleDocs[10],InstructionDocs[4]),\n            new Op(0x0F,\"SLO\",\"a\"       ,3,nFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[10],InstructionDocs[5]),\n            new Op(0x10,\"BPL\",\"r\"       ,2,pcChanges                                    ,CycleDocs[21],InstructionDocs[8]),\n            new Op(0x11,\"ORA\",\"(d),y\"   ,2,nFlag | zFlag | aChanges                     ,CycleDocs[25],InstructionDocs[1]),\n            new Op(0x12,\"HLT\",\"i\"       ,1,0                                            ,CycleDocs[29],InstructionDocs[2]),\n            new Op(0x13,\"SLO\",\"(d),y\"   ,2,nFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[26],InstructionDocs[5]),\n            new Op(0x14,\"NOP\",\"d,x\"     ,2,0                                            ,CycleDocs[15],InstructionDocs[3]),\n            new Op(0x15,\"ORA\",\"d,x\"     ,2,nFlag | zFlag | aChanges                     ,CycleDocs[15],InstructionDocs[1]),\n            new Op(0x16,\"ASL\",\"d,x\"     ,2,nFlag | zFlag | cFlag | memChanges           ,CycleDocs[16],InstructionDocs[4]),\n            new Op(0x17,\"SLO\",\"d,x\"     ,2,nFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[16],InstructionDocs[5]),\n            new Op(0x18,\"CLC\",\"i\"       ,1,cFlag                                        ,CycleDocs[6] ,InstructionDocs[9]),\n            new Op(0x19,\"ORA\",\"a,y\"     ,3,nFlag | zFlag | aChanges                     ,CycleDocs[18],InstructionDocs[1]),\n            new Op(0x1A,\"NOP\",\"i\"       ,1,0                                            ,CycleDocs[6] ,InstructionDocs[3]),\n            new Op(0x1B,\"SLO\",\"a,y\"     ,3,nFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[19],InstructionDocs[5]),\n            new Op(0x1C,\"NOP\",\"a,x\"     ,3,0                                            ,CycleDocs[18],InstructionDocs[3]),\n            new Op(0x1D,\"ORA\",\"a,x\"     ,3,nFlag | zFlag | aChanges                     ,CycleDocs[18],InstructionDocs[1]),\n            new Op(0x1E,\"ASL\",\"a,x\"     ,3,nFlag | zFlag | cFlag | memChanges           ,CycleDocs[19],InstructionDocs[4]),\n            new Op(0x1F,\"SLO\",\"a,x\"     ,3,nFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[19],InstructionDocs[5]),\n\n            new Op(0x20,\"JSR\",\"a\"       ,3,stackPChanges | pcChanges                    ,CycleDocs[5] ,InstructionDocs[10]),\n            new Op(0x21,\"AND\",\"(d,x)\"   ,2,nFlag | zFlag | aChanges                     ,CycleDocs[22],InstructionDocs[11]),\n            new Op(0x22,\"HLT\",\"i\"       ,1,0                                            ,CycleDocs[29],InstructionDocs[2]),\n            new Op(0x23,\"RLA\",\"(d,x)\"   ,2,nFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[23],InstructionDocs[12]),\n            new Op(0x24,\"BIT\",\"d\"       ,2,nFlag | zFlag | cFlag | vFlag                ,CycleDocs[12],InstructionDocs[13]),\n            new Op(0x25,\"AND\",\"d\"       ,2,nFlag | zFlag | aChanges                     ,CycleDocs[12],InstructionDocs[11]),\n            new Op(0x26,\"ROL\",\"d\"       ,2,nFlag | zFlag | cFlag | memChanges           ,CycleDocs[13],InstructionDocs[14]),\n            new Op(0x27,\"RLA\",\"d\"       ,2,nFlag | zFlag | cFlag | aChanges             ,CycleDocs[13],InstructionDocs[12]),\n            new Op(0x28,\"PLP\",\"i\"       ,1,cFlag|zFlag|iFlag|dFlag|vFlag|nFlag,CycleDocs[4],InstructionDocs[15]),\n            new Op(0x29,\"AND\",\"#v\"      ,2,nFlag | zFlag | aChanges                     ,CycleDocs[7] ,InstructionDocs[11]),\n            new Op(0x2A,\"ROL\",\"A\"       ,1,nFlag | zFlag | cFlag | aChanges             ,CycleDocs[6] ,InstructionDocs[14]),\n            new Op(0x2B,\"ANC\",\"#v\"      ,2,nFlag | zFlag | cFlag | aChanges             ,CycleDocs[7] ,InstructionDocs[7]),\n            new Op(0x2C,\"BIT\",\"a\"       ,3,nFlag | zFlag | cFlag | vFlag                ,CycleDocs[9] ,InstructionDocs[13]),\n            new Op(0x2D,\"AND\",\"a\"       ,3,nFlag | zFlag | aChanges                     ,CycleDocs[9] ,InstructionDocs[11]),\n            new Op(0x2E,\"ROL\",\"a\"       ,3,nFlag | zFlag | cFlag | memChanges           ,CycleDocs[10],InstructionDocs[14]),\n            new Op(0x2F,\"RLA\",\"a\"       ,3,nFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[10],InstructionDocs[12]),\n            new Op(0x30,\"BMI\",\"r\"       ,2,pcChanges                                    ,CycleDocs[21],InstructionDocs[16]),\n            new Op(0x31,\"AND\",\"(d),y\"   ,2,nFlag | zFlag | aChanges                     ,CycleDocs[25],InstructionDocs[11]),\n            new Op(0x32,\"HLT\",\"i\"       ,1,0                                            ,CycleDocs[29],InstructionDocs[2]),\n            new Op(0x33,\"RLA\",\"(d),y\"   ,2,nFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[26],InstructionDocs[12]),\n            new Op(0x34,\"NOP\",\"d,x\"     ,2,0                                            ,CycleDocs[15],InstructionDocs[3]),\n            new Op(0x35,\"AND\",\"d,x\"     ,2,nFlag | zFlag | aChanges                     ,CycleDocs[15],InstructionDocs[11]),\n            new Op(0x36,\"ROL\",\"d,x\"     ,2,nFlag | zFlag | cFlag | memChanges           ,CycleDocs[16],InstructionDocs[14]),\n            new Op(0x37,\"RLA\",\"d,x\"     ,2,nFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[16],InstructionDocs[12]),\n            new Op(0x38,\"SEC\",\"i\"       ,1,cFlag                                        ,CycleDocs[6] ,InstructionDocs[17]),\n            new Op(0x39,\"AND\",\"a,y\"     ,3,nFlag | zFlag | aChanges                     ,CycleDocs[18],InstructionDocs[11]),\n            new Op(0x3A,\"NOP\",\"i\"       ,1,0                                            ,CycleDocs[6] ,InstructionDocs[3]),\n            new Op(0x3B,\"RLA\",\"a,y\"     ,3,nFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[19],InstructionDocs[12]),\n            new Op(0x3C,\"NOP\",\"a,x\"     ,3,0                                            ,CycleDocs[18],InstructionDocs[3]),\n            new Op(0x3D,\"AND\",\"a,x\"     ,3,nFlag | zFlag | aChanges                     ,CycleDocs[18],InstructionDocs[11]),\n            new Op(0x3E,\"ROL\",\"a,x\"     ,3,nFlag | zFlag | cFlag | memChanges           ,CycleDocs[19],InstructionDocs[14]),\n            new Op(0x3F,\"RLA\",\"a,x\"     ,3,nFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[19],InstructionDocs[12]),\n\n            new Op(0x40,\"RTI\",\"i\"       ,1,0xFF | stackPChanges | pcChanges             ,CycleDocs[1] ,InstructionDocs[18]),\n            new Op(0x41,\"EOR\",\"(d,x)\"   ,2,nFlag | zFlag | aChanges                     ,CycleDocs[22],InstructionDocs[19]),\n            new Op(0x42,\"HLT\",\"i\"       ,1,0                                            ,CycleDocs[29],InstructionDocs[2]),\n            new Op(0x43,\"SRE\",\"(d,x)\"   ,2,nFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[23],InstructionDocs[20]),\n            new Op(0x44,\"NOP\",\"d\"       ,2,0                                            ,CycleDocs[12],InstructionDocs[3]),\n            new Op(0x45,\"EOR\",\"d\"       ,2,nFlag | zFlag | aChanges                     ,CycleDocs[12],InstructionDocs[19]),\n            new Op(0x46,\"LSR\",\"d\"       ,2,nFlag | zFlag | cFlag | memChanges           ,CycleDocs[13],InstructionDocs[21]),\n            new Op(0x47,\"SRE\",\"d\"       ,2,nFlag | zFlag | cFlag                        ,CycleDocs[13],InstructionDocs[20]),\n            new Op(0x48,\"PHA\",\"i\"       ,1,stackPChanges                                ,CycleDocs[3] ,InstructionDocs[22]),\n            new Op(0x49,\"EOR\",\"#v\"      ,2,nFlag | zFlag                                ,CycleDocs[7] ,InstructionDocs[19]),\n            new Op(0x4A,\"LSR\",\"A\"       ,1,nFlag | zFlag | cFlag | aChanges             ,CycleDocs[6] ,InstructionDocs[21]),\n            new Op(0x4B,\"ASR\",\"#v\"      ,2,nFlag | zFlag | cFlag | aChanges             ,CycleDocs[7] ,InstructionDocs[23]),\n            new Op(0x4C,\"JMP\",\"a\"       ,3,0                                            ,CycleDocs[8] ,InstructionDocs[24]),\n            new Op(0x4D,\"EOR\",\"a\"       ,3,nFlag | zFlag | aChanges                     ,CycleDocs[9] ,InstructionDocs[19]),\n            new Op(0x4E,\"LSR\",\"a\"       ,3,nFlag | zFlag | cFlag | memChanges           ,CycleDocs[10],InstructionDocs[21]),\n            new Op(0x4F,\"SRE\",\"a\"       ,3,nFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[10],InstructionDocs[20]),\n            new Op(0x50,\"BVC\",\"r\"       ,2,pcChanges                                    ,CycleDocs[21],InstructionDocs[25]),\n            new Op(0x51,\"EOR\",\"(d),y\"   ,2,nFlag | zFlag | aChanges                     ,CycleDocs[25],InstructionDocs[19]),\n            new Op(0x52,\"HLT\",\"i\"       ,1,0                                            ,CycleDocs[29],InstructionDocs[2]),\n            new Op(0x53,\"SRE\",\"(d),y\"   ,2,nFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[26],InstructionDocs[20]),\n            new Op(0x54,\"NOP\",\"d,x\"     ,2,0                                            ,CycleDocs[15],InstructionDocs[3]),\n            new Op(0x55,\"EOR\",\"d,x\"     ,2,nFlag | zFlag | aChanges                     ,CycleDocs[15],InstructionDocs[19]),\n            new Op(0x56,\"LSR\",\"d,x\"     ,2,nFlag | zFlag | cFlag | memChanges           ,CycleDocs[16],InstructionDocs[21]),\n            new Op(0x57,\"SRE\",\"d,x\"     ,2,nFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[16],InstructionDocs[20]),\n            new Op(0x58,\"CLI\",\"i\"       ,1,iFlag                                        ,CycleDocs[6] ,InstructionDocs[26]),\n            new Op(0x59,\"EOR\",\"a,y\"     ,3,nFlag | zFlag | aChanges                     ,CycleDocs[18],InstructionDocs[19]),\n            new Op(0x5A,\"NOP\",\"i\"       ,1,0                                            ,CycleDocs[6] ,InstructionDocs[3]),\n            new Op(0x5B,\"SRE\",\"a,y\"     ,3,nFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[19],InstructionDocs[20]),\n            new Op(0x5C,\"NOP\",\"a,x\"     ,3,0                                            ,CycleDocs[18],InstructionDocs[3]),\n            new Op(0x5D,\"EOR\",\"a,x\"     ,3,nFlag | zFlag | aChanges                     ,CycleDocs[18],InstructionDocs[19]),\n            new Op(0x5E,\"LSR\",\"a,x\"     ,3,nFlag | zFlag | cFlag | memChanges           ,CycleDocs[19],InstructionDocs[21]),\n            new Op(0x5F,\"SRE\",\"a,x\"     ,3,nFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[19],InstructionDocs[20]),\n\n            new Op(0x60,\"RTS\",\"i\"       ,1,stackPChanges | pcChanges                            ,CycleDocs[2] ,InstructionDocs[27]),\n            new Op(0x61,\"ADC\",\"(d,x)\"   ,2,nFlag | vFlag | zFlag | cFlag | aChanges             ,CycleDocs[22],InstructionDocs[28]),\n            new Op(0x62,\"HLT\",\"i\"       ,1,0                                                    ,CycleDocs[29],InstructionDocs[2]),\n            new Op(0x63,\"RRA\",\"(d,x)\"   ,2,nFlag | vFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[23],InstructionDocs[29]),\n            new Op(0x64,\"NOP\",\"d\"       ,2,0                                                    ,CycleDocs[12],InstructionDocs[3]),\n            new Op(0x65,\"ADC\",\"d\"       ,2,nFlag | vFlag | zFlag | cFlag | aChanges             ,CycleDocs[12],InstructionDocs[28]),\n            new Op(0x66,\"ROR\",\"d\"       ,2,nFlag | zFlag | cFlag | memChanges                   ,CycleDocs[13],InstructionDocs[30]),\n            new Op(0x67,\"RRA\",\"d\"       ,2,nFlag | vFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[13],InstructionDocs[29]),\n            new Op(0x68,\"PLA\",\"i\"       ,1,stackPChanges | aChanges                             ,CycleDocs[4] ,InstructionDocs[31]),\n            new Op(0x69,\"ADC\",\"#v\"      ,2,nFlag | vFlag | zFlag | cFlag | aChanges             ,CycleDocs[7] ,InstructionDocs[28]),\n            new Op(0x6A,\"ROR\",\"A\"       ,1,nFlag | zFlag | cFlag | aChanges                     ,CycleDocs[6] ,InstructionDocs[30]),\n            new Op(0x6B,\"ARR\",\"#v\"      ,2,nFlag | vFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[7] ,InstructionDocs[32]),\n            new Op(0x6C,\"JMP\",\"(a)\"     ,3,0                                                    ,CycleDocs[28],InstructionDocs[24]),\n            new Op(0x6D,\"ADC\",\"a\"       ,3,nFlag | vFlag | zFlag | cFlag | aChanges             ,CycleDocs[9] ,InstructionDocs[28]),\n            new Op(0x6E,\"ROR\",\"a\"       ,3,nFlag | zFlag | cFlag | memChanges                   ,CycleDocs[10],InstructionDocs[30]),\n            new Op(0x6F,\"RRA\",\"a\"       ,3,nFlag | vFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[10],InstructionDocs[29]),\n            new Op(0x70,\"BVS\",\"r\"       ,2,pcChanges                                            ,CycleDocs[21],InstructionDocs[33]),\n            new Op(0x71,\"ADC\",\"(d),y\"   ,2,nFlag | vFlag | zFlag | cFlag | aChanges             ,CycleDocs[25],InstructionDocs[28]),\n            new Op(0x72,\"HLT\",\"i\"       ,1,0                                                    ,CycleDocs[29],InstructionDocs[2]),\n            new Op(0x73,\"RRA\",\"(d),y\"   ,2,nFlag | vFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[26],InstructionDocs[29]),\n            new Op(0x74,\"NOP\",\"d,x\"     ,2,0                                                    ,CycleDocs[15],InstructionDocs[3]),\n            new Op(0x75,\"ADC\",\"d,x\"     ,2,nFlag | vFlag | zFlag | cFlag | aChanges             ,CycleDocs[15],InstructionDocs[28]),\n            new Op(0x76,\"ROR\",\"d,x\"     ,2,nFlag | zFlag | cFlag | memChanges                   ,CycleDocs[16],InstructionDocs[30]),\n            new Op(0x77,\"RRA\",\"d,x\"     ,2,nFlag | vFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[16],InstructionDocs[29]),\n            new Op(0x78,\"SEI\",\"i\"       ,1,iFlag                                                ,CycleDocs[6] ,InstructionDocs[34]),\n            new Op(0x79,\"ADC\",\"a,y\"     ,3,nFlag | vFlag | zFlag | cFlag | aChanges             ,CycleDocs[18],InstructionDocs[28]),\n            new Op(0x7A,\"NOP\",\"i\"       ,1,0                                                    ,CycleDocs[6] ,InstructionDocs[3]),\n            new Op(0x7B,\"RRA\",\"a,y\"     ,3,nFlag | vFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[19],InstructionDocs[29]),\n            new Op(0x7C,\"NOP\",\"a,x\"     ,3,0                                                    ,CycleDocs[18],InstructionDocs[3]),\n            new Op(0x7D,\"ADC\",\"a,x\"     ,3,nFlag | vFlag | zFlag | cFlag | aChanges             ,CycleDocs[18],InstructionDocs[28]),\n            new Op(0x7E,\"ROR\",\"a,x\"     ,3,nFlag | zFlag | cFlag | memChanges                   ,CycleDocs[19],InstructionDocs[30]),\n            new Op(0x7F,\"RRA\",\"a,x\"     ,3,nFlag | vFlag | zFlag | cFlag | aChanges | memChanges,CycleDocs[19],InstructionDocs[29]),\n\n            new Op(0x80,\"NOP\",\"#v\"      ,2,0                        ,CycleDocs[7] ,InstructionDocs[3]),\n            new Op(0x81,\"STA\",\"(d,x)\"   ,2,memChanges               ,CycleDocs[24],InstructionDocs[35]),\n            new Op(0x82,\"NOP\",\"#v\"      ,2,0                        ,CycleDocs[7] ,InstructionDocs[3]),\n            new Op(0x83,\"SAX\",\"(d,x)\"   ,2,memChanges               ,CycleDocs[24],InstructionDocs[36]),\n            new Op(0x84,\"STY\",\"d\"       ,2,memChanges               ,CycleDocs[14],InstructionDocs[37]),\n            new Op(0x85,\"STA\",\"d\"       ,2,memChanges               ,CycleDocs[14],InstructionDocs[35]),\n            new Op(0x86,\"STX\",\"d\"       ,2,memChanges               ,CycleDocs[14],InstructionDocs[38]),\n            new Op(0x87,\"SAX\",\"d\"       ,2,memChanges               ,CycleDocs[14],InstructionDocs[36]),\n            new Op(0x88,\"DEY\",\"i\"       ,1,yChanges | nFlag | zFlag ,CycleDocs[6] ,InstructionDocs[39]),\n            new Op(0x89,\"NOP\",\"#v\"      ,2,0                        ,CycleDocs[7] ,InstructionDocs[3]),\n            new Op(0x8A,\"TXA\",\"i\"       ,1,aChanges | nFlag | zFlag ,CycleDocs[7] ,InstructionDocs[40]),\n            new Op(0x8B,\"ANE\",\"#v\"      ,2,aChanges | nFlag | zFlag ,CycleDocs[7] ,InstructionDocs[41]),\n            new Op(0x8C,\"STY\",\"a\"       ,3,memChanges               ,CycleDocs[11],InstructionDocs[37]),\n            new Op(0x8D,\"STA\",\"a\"       ,3,memChanges               ,CycleDocs[11],InstructionDocs[35]),\n            new Op(0x8E,\"STX\",\"a\"       ,3,memChanges               ,CycleDocs[11],InstructionDocs[38]),\n            new Op(0x8F,\"SAX\",\"a\"       ,3,memChanges               ,CycleDocs[11],InstructionDocs[36]),\n            new Op(0x90,\"BCC\",\"r\"       ,2,pcChanges                ,CycleDocs[21],InstructionDocs[42]),\n            new Op(0x91,\"STA\",\"(d),y\"   ,2,memChanges               ,CycleDocs[27],InstructionDocs[35]),\n            new Op(0x92,\"HLT\",\"i\"       ,1,memChanges               ,CycleDocs[29],InstructionDocs[2]),\n            new Op(0x93,\"SHA\",\"(d),y\"   ,2,memChanges               ,CycleDocs[27],InstructionDocs[44]),\n            new Op(0x94,\"STY\",\"d,x\"     ,2,memChanges               ,CycleDocs[17],InstructionDocs[37]),\n            new Op(0x95,\"STA\",\"d,x\"     ,2,memChanges               ,CycleDocs[17],InstructionDocs[35]),\n            new Op(0x96,\"STX\",\"d,y\"     ,2,memChanges               ,CycleDocs[17],InstructionDocs[38]),\n            new Op(0x97,\"SAX\",\"d,y\"     ,2,memChanges               ,CycleDocs[17],InstructionDocs[36]),\n            new Op(0x98,\"TYA\",\"i\"       ,1,aChanges | nFlag | zFlag ,CycleDocs[6] ,InstructionDocs[45]),\n            new Op(0x99,\"STA\",\"a,y\"     ,3,memChanges               ,CycleDocs[20],InstructionDocs[35]),\n            new Op(0x9A,\"TXS\",\"i\"       ,1,stackPChanges            ,CycleDocs[6] ,InstructionDocs[43]),\n            new Op(0x9B,\"SHS\",\"a,y\"     ,3,stackPChanges | memChanges,CycleDocs[20],InstructionDocs[47]),\n            new Op(0x9C,\"SHY\",\"a,x\"     ,3,memChanges               ,CycleDocs[20],InstructionDocs[46]),\n            new Op(0x9D,\"STA\",\"a,x\"     ,3,memChanges               ,CycleDocs[20],InstructionDocs[35]),\n            new Op(0x9E,\"SHX\",\"a,y\"     ,3,memChanges               ,CycleDocs[20],InstructionDocs[48]),\n            new Op(0x9F,\"SHA\",\"a,y\"     ,3,memChanges               ,CycleDocs[20],InstructionDocs[44]),\n\n            new Op(0xA0,\"LDY\",\"#v\"      ,2,yChanges | nFlag | zFlag                             ,CycleDocs[7] ,InstructionDocs[49]),\n            new Op(0xA1,\"LDA\",\"(d,x)\"   ,2,aChanges | nFlag | zFlag                             ,CycleDocs[22],InstructionDocs[50]),\n            new Op(0xA2,\"LDX\",\"#v\"      ,2,xChanges | nFlag | zFlag                             ,CycleDocs[7] ,InstructionDocs[51]),\n            new Op(0xA3,\"LAX\",\"(d,x)\"   ,2,xChanges | aChanges | nFlag | zFlag                  ,CycleDocs[22],InstructionDocs[52]),\n            new Op(0xA4,\"LDY\",\"d\"       ,2,yChanges | nFlag | zFlag                             ,CycleDocs[12],InstructionDocs[49]),\n            new Op(0xA5,\"LDA\",\"d\"       ,2,aChanges | nFlag | zFlag                             ,CycleDocs[12],InstructionDocs[50]),\n            new Op(0xA6,\"LDX\",\"d\"       ,2,xChanges | nFlag | zFlag                             ,CycleDocs[12],InstructionDocs[51]),\n            new Op(0xA7,\"LAX\",\"d\"       ,2,xChanges | aChanges | nFlag | zFlag                  ,CycleDocs[12],InstructionDocs[52]),\n            new Op(0xA8,\"TAY\",\"i\"       ,1,yChanges | nFlag | zFlag                             ,CycleDocs[6] ,InstructionDocs[53]),\n            new Op(0xA9,\"LDA\",\"#v\"      ,2,aChanges | nFlag | zFlag                             ,CycleDocs[7] ,InstructionDocs[50]),\n            new Op(0xAA,\"TAX\",\"i\"       ,1,xChanges | nFlag | zFlag                             ,CycleDocs[6] ,InstructionDocs[54]),\n            new Op(0xAB,\"LXA\",\"#v\"      ,2,xChanges | aChanges | nFlag | zFlag                  ,CycleDocs[7] ,InstructionDocs[55]),\n            new Op(0xAC,\"LDY\",\"a\"       ,3,yChanges | nFlag | zFlag                             ,CycleDocs[9] ,InstructionDocs[49]),\n            new Op(0xAD,\"LDA\",\"a\"       ,3,aChanges | nFlag | zFlag                             ,CycleDocs[9] ,InstructionDocs[50]),\n            new Op(0xAE,\"LDX\",\"a\"       ,3,xChanges | nFlag | zFlag                             ,CycleDocs[10],InstructionDocs[51]),\n            new Op(0xAF,\"LAX\",\"a\"       ,3,xChanges | aChanges | nFlag | zFlag                  ,CycleDocs[10],InstructionDocs[52]),\n            new Op(0xB0,\"BCS\",\"r\"       ,2,pcChanges                                            ,CycleDocs[21],InstructionDocs[56]),\n            new Op(0xB1,\"LDA\",\"(d),y\"   ,2,aChanges | nFlag | zFlag                             ,CycleDocs[25],InstructionDocs[50]),\n            new Op(0xB2,\"HLT\",\"i\"       ,1,0                                                    ,CycleDocs[29],InstructionDocs[2]),\n            new Op(0xB3,\"LAX\",\"(d),y\"   ,2,xChanges | aChanges | nFlag | zFlag                  ,CycleDocs[25],InstructionDocs[52]),\n            new Op(0xB4,\"LDY\",\"d,x\"     ,2,yChanges | nFlag | zFlag                             ,CycleDocs[15],InstructionDocs[49]),\n            new Op(0xB5,\"LDA\",\"d,x\"     ,2,aChanges | nFlag | zFlag                             ,CycleDocs[15],InstructionDocs[50]),\n            new Op(0xB6,\"LDX\",\"d,y\"     ,2,xChanges | nFlag | zFlag                             ,CycleDocs[15],InstructionDocs[51]),\n            new Op(0xB7,\"LAX\",\"d,y\"     ,2,xChanges | aChanges | nFlag | zFlag                  ,CycleDocs[15],InstructionDocs[52]),\n            new Op(0xB8,\"CLV\",\"i\"       ,1,vFlag                                                ,CycleDocs[6] ,InstructionDocs[57]),\n            new Op(0xB9,\"LDA\",\"a,y\"     ,3,aChanges | nFlag | zFlag                             ,CycleDocs[18],InstructionDocs[50]),\n            new Op(0xBA,\"TSX\",\"i\"       ,1,xChanges | nFlag | zFlag                             ,CycleDocs[6] ,InstructionDocs[58]),\n            new Op(0xBB,\"LAS\",\"a,y\"     ,3,nFlag | zFlag | aChanges | xChanges | stackPChanges  ,CycleDocs[18],InstructionDocs[59]),\n            new Op(0xBC,\"LDY\",\"a,x\"     ,3,yChanges | nFlag | zFlag                             ,CycleDocs[18],InstructionDocs[49]),\n            new Op(0xBD,\"LDA\",\"a,x\"     ,3,aChanges | nFlag | zFlag                             ,CycleDocs[18],InstructionDocs[50]),\n            new Op(0xBE,\"LDX\",\"a,y\"     ,3,xChanges | nFlag | zFlag                             ,CycleDocs[18],InstructionDocs[51]),\n            new Op(0xBF,\"LAX\",\"a,y\"     ,3,xChanges | aChanges | nFlag | zFlag                  ,CycleDocs[18],InstructionDocs[52]),\n\n            new Op(0xC0,\"CPY\",\"#v\"      ,2,nFlag | zFlag | cFlag                ,CycleDocs[7] ,InstructionDocs[60]),\n            new Op(0xC1,\"CMP\",\"(d,x)\"   ,2,nFlag | zFlag | cFlag                ,CycleDocs[22],InstructionDocs[61]),\n            new Op(0xC2,\"NOP\",\"#v\"      ,2,0                                    ,CycleDocs[7] ,InstructionDocs[3]),\n            new Op(0xC3,\"DCP\",\"(d,x)\"   ,2,memChanges | nFlag | zFlag | cFlag   ,CycleDocs[23],InstructionDocs[62]),\n            new Op(0xC4,\"CPY\",\"d\"       ,2,nFlag | zFlag | cFlag                ,CycleDocs[12],InstructionDocs[60]),\n            new Op(0xC5,\"CMP\",\"d\"       ,2,nFlag | zFlag | cFlag                ,CycleDocs[12],InstructionDocs[61]),\n            new Op(0xC6,\"DEC\",\"d\"       ,2,memChanges | nFlag | zFlag           ,CycleDocs[13],InstructionDocs[63]),\n            new Op(0xC7,\"DCP\",\"d\"       ,2,memChanges | nFlag | zFlag | cFlag   ,CycleDocs[13],InstructionDocs[62]),\n            new Op(0xC8,\"INY\",\"i\"       ,1,yChanges | nFlag | zFlag             ,CycleDocs[6] ,InstructionDocs[64]),\n            new Op(0xC9,\"CMP\",\"#v\"      ,2,nFlag | zFlag | cFlag                ,CycleDocs[7] ,InstructionDocs[61]),\n            new Op(0xCA,\"DEX\",\"i\"       ,1,xChanges | nFlag | zFlag             ,CycleDocs[6] ,InstructionDocs[65]),\n            new Op(0xCB,\"AXS\",\"#v\"      ,2,memChanges  | nFlag | cFlag | zFlag  ,CycleDocs[7] ,InstructionDocs[66]),\n            new Op(0xCC,\"CPY\",\"a\"       ,3,nFlag | zFlag | cFlag                ,CycleDocs[9] ,InstructionDocs[60]),\n            new Op(0xCD,\"CMP\",\"a\"       ,3,nFlag | zFlag | cFlag                ,CycleDocs[9] ,InstructionDocs[61]),\n            new Op(0xCE,\"DEC\",\"a\"       ,3,memChanges | nFlag | zFlag           ,CycleDocs[10],InstructionDocs[63]),\n            new Op(0xCF,\"DCP\",\"a\"       ,3,memChanges | nFlag | zFlag | cFlag   ,CycleDocs[10],InstructionDocs[62]),\n            new Op(0xD0,\"BNE\",\"r\"       ,2,pcChanges                            ,CycleDocs[21],InstructionDocs[67]),\n            new Op(0xD1,\"CMP\",\"(d),y\"   ,2,nFlag | zFlag | cFlag                ,CycleDocs[25],InstructionDocs[61]),\n            new Op(0xD2,\"HLT\",\"i\"       ,1,0                                    ,CycleDocs[29],InstructionDocs[2]),\n            new Op(0xD3,\"DCP\",\"(d),y\"   ,2,memChanges | nFlag | zFlag | cFlag   ,CycleDocs[26],InstructionDocs[62]),\n            new Op(0xD4,\"NOP\",\"d,x\"     ,2,0                                    ,CycleDocs[15],InstructionDocs[3]),\n            new Op(0xD5,\"CMP\",\"d,x\"     ,2,nFlag | zFlag | cFlag                ,CycleDocs[15],InstructionDocs[61]),\n            new Op(0xD6,\"DEC\",\"d,x\"     ,2,memChanges | nFlag | zFlag           ,CycleDocs[16],InstructionDocs[63]),\n            new Op(0xD7,\"DCP\",\"d,x\"     ,2,memChanges | nFlag | zFlag | cFlag   ,CycleDocs[16],InstructionDocs[62]),\n            new Op(0xD8,\"CLD\",\"i\"       ,1,dFlag                                ,CycleDocs[6] ,InstructionDocs[68]),\n            new Op(0xD9,\"CMP\",\"a,y\"     ,3,nFlag | zFlag | cFlag                ,CycleDocs[18],InstructionDocs[61]),\n            new Op(0xDA,\"NOP\",\"i\"       ,1,0                                    ,CycleDocs[6] ,InstructionDocs[3]),\n            new Op(0xDB,\"DCP\",\"a,x\"     ,3,memChanges | nFlag | zFlag | cFlag   ,CycleDocs[19],InstructionDocs[62]),\n            new Op(0xDC,\"NOP\",\"a,x\"     ,3,0                                    ,CycleDocs[18],InstructionDocs[3]),\n            new Op(0xDD,\"CMP\",\"a,x\"     ,3,nFlag | zFlag | cFlag                ,CycleDocs[18],InstructionDocs[61]),\n            new Op(0xDE,\"DEC\",\"a,x\"     ,3,memChanges | nFlag | zFlag           ,CycleDocs[19],InstructionDocs[63]),\n            new Op(0xDF,\"DCP\",\"a,x\"     ,3,memChanges | nFlag | zFlag | cFlag   ,CycleDocs[19],InstructionDocs[62]),\n\n            new Op(0xE0,\"CPX\",\"#v\"      ,2,nFlag | zFlag | cFlag                                ,CycleDocs[7] ,InstructionDocs[69]),\n            new Op(0xE1,\"SBC\",\"(d,x)\"   ,2,aChanges | nFlag | zFlag | cFlag | vFlag             ,CycleDocs[22],InstructionDocs[70]),\n            new Op(0xE2,\"NOP\",\"#v\"      ,2,0                                                    ,CycleDocs[7] ,InstructionDocs[3]),\n            new Op(0xE3,\"ISC\",\"(d,x)\"   ,2,aChanges | memChanges | nFlag | zFlag | cFlag | vFlag,CycleDocs[23],InstructionDocs[71]),\n            new Op(0xE4,\"CPX\",\"d\"       ,2,nFlag | zFlag | cFlag                                ,CycleDocs[12],InstructionDocs[69]),\n            new Op(0xE5,\"SBC\",\"d\"       ,2,aChanges | nFlag | zFlag | cFlag | vFlag             ,CycleDocs[12],InstructionDocs[70]),\n            new Op(0xE6,\"INC\",\"d\"       ,2,memChanges | nFlag | zFlag                           ,CycleDocs[13],InstructionDocs[72]),\n            new Op(0xE7,\"ISC\",\"d\"       ,2,aChanges | memChanges | nFlag | zFlag | cFlag | vFlag,CycleDocs[13],InstructionDocs[71]),\n            new Op(0xE8,\"INX\",\"i\"       ,1,xChanges | nFlag | zFlag                             ,CycleDocs[6] ,InstructionDocs[73]),\n            new Op(0xE9,\"SBC\",\"#v\"      ,2,aChanges | nFlag | zFlag | cFlag | vFlag             ,CycleDocs[7] ,InstructionDocs[70]),\n            new Op(0xEA,\"NOP\",\"i\"       ,1,0                                                    ,CycleDocs[6] ,InstructionDocs[3]),\n            new Op(0xEB,\"SBC\",\"#v\"      ,2,aChanges | nFlag | zFlag | cFlag | vFlag             ,CycleDocs[7] ,InstructionDocs[70]),\n            new Op(0xEC,\"CPX\",\"a\"       ,3,nFlag | zFlag | cFlag                                ,CycleDocs[9] ,InstructionDocs[69]),\n            new Op(0xED,\"SBC\",\"a\"       ,3,aChanges | nFlag | zFlag | cFlag | vFlag             ,CycleDocs[9] ,InstructionDocs[70]),\n            new Op(0xEE,\"INC\",\"a\"       ,3,memChanges | nFlag | zFlag                           ,CycleDocs[10],InstructionDocs[72]),\n            new Op(0xEF,\"ISC\",\"a\"       ,3,aChanges | memChanges | nFlag | zFlag | cFlag | vFlag,CycleDocs[10],InstructionDocs[71]),\n            new Op(0xF0,\"BEQ\",\"r\"       ,2,pcChanges                                            ,CycleDocs[21],InstructionDocs[74]),\n            new Op(0xF1,\"SBC\",\"(d),y\"   ,2,aChanges | nFlag | zFlag | cFlag | vFlag             ,CycleDocs[25],InstructionDocs[70]),\n            new Op(0xF2,\"HLT\",\"i\"       ,1,0                                                    ,CycleDocs[29],InstructionDocs[2]),\n            new Op(0xF3,\"ISC\",\"(d),y\"   ,2,aChanges | memChanges | nFlag | zFlag | cFlag | vFlag,CycleDocs[26],InstructionDocs[71]),\n            new Op(0xF4,\"NOP\",\"d,x\"     ,2,0                                                    ,CycleDocs[15],InstructionDocs[3]),\n            new Op(0xF5,\"SBC\",\"d,x\"     ,2,aChanges | nFlag | zFlag | cFlag | vFlag             ,CycleDocs[15],InstructionDocs[70]),\n            new Op(0xF6,\"INC\",\"d,x\"     ,2,memChanges | nFlag | zFlag                           ,CycleDocs[16],InstructionDocs[72]),\n            new Op(0xF7,\"ISC\",\"d,x\"     ,2,aChanges | memChanges | nFlag | zFlag | cFlag | vFlag,CycleDocs[16],InstructionDocs[71]),\n            new Op(0xF8,\"SED\",\"i\"       ,1,dFlag                                                ,CycleDocs[6] ,InstructionDocs[75]),\n            new Op(0xF9,\"SBC\",\"a,y\"     ,3,aChanges | nFlag | zFlag | cFlag | vFlag             ,CycleDocs[18],InstructionDocs[70]),\n            new Op(0xFA,\"NOP\",\"i\"       ,1,0                                                    ,CycleDocs[6] ,InstructionDocs[3]),\n            new Op(0xFB,\"ISC\",\"a,x\"     ,3,aChanges | memChanges | nFlag | zFlag | cFlag | vFlag,CycleDocs[19],InstructionDocs[71]),\n            new Op(0xFC,\"NOP\",\"a,x\"     ,3,0                                                    ,CycleDocs[18],InstructionDocs[3]),\n            new Op(0xFD,\"SBC\",\"a,x\"     ,3,aChanges | nFlag | zFlag | cFlag | vFlag             ,CycleDocs[18],InstructionDocs[70]),\n            new Op(0xFE,\"INC\",\"a,x\"     ,3,memChanges | nFlag | zFlag                           ,CycleDocs[19],InstructionDocs[72]),\n            new Op(0xFF,\"ISC\",\"a,x\"     ,3,aChanges | memChanges | nFlag | zFlag | cFlag | vFlag,CycleDocs[19],InstructionDocs[71])\n            };\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n    }\n}\n"
  },
  {
    "path": "App.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n\t<dllmap dll=\"SDL2\" os=\"windows\" target=\"SDL2.dll\"/>\n\t<dllmap dll=\"SDL2\" os=\"osx\" target=\"libSDL2.dylib\"/>\n\t<dllmap dll=\"SDL2\" os=\"linux\" target=\"libSDL2-2.0.so.0\"/>\n</configuration>\n"
  },
  {
    "path": "Emulator.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.Drawing.Imaging;\nusing System.IO;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing TriCNES.mappers;\n\nnamespace TriCNES\n{\n    // Coin's Contrabulous Cartswapulator!\n    public class Cartridge\n    {\n        // Since I made this emulator with mid-instruction cartridge swapping in mind, the cartridge class holds information about the cartridge that would persist when swapped in and out.\n\n        public Emulator Emu;        // Mostly for triggering / clearing the IRQ from mapper function.\n\n        public string Name;         // For debugging\n        public byte[] ROM;          // The entire .nes file\n\n        public byte[] PRGROM;       // The entire program rom portion of the .nes file\n        public byte[] CHRROM;       // The entire character rom portion of the .nes file\n\n        public byte MemoryMapper;   // Header info: what mapper chip is this cartridge using?\n        public byte SubMapper;      // Header Info: what variant of the mapper chip are we using?\n        public byte PRG_Size;       // Header info: how many kb of PRG data does this cartridge have?\n        public byte CHR_Size;       // Header info: how many kb of CHR data does this cartridge have?\n        public byte PRG_SizeMinus1; // PRG_Size-1; This is frequently used when grabbing data from PRG banks\n\n        public byte[] CHRRAM;       // If this cartridge has character RAM, this array is used.\n        public bool UsingCHRRAM;    // Header info: CHR RAM doesn't exist on all cartridges.\n\n        public byte[] PRGRAM;       // PRG RAM / Battery backed save RAM.\n        public bool AlternativeNametableArrangement; // Header info: Some mapper chips support \"alternative nametable arrangements\", which are mapper-specific.\n        public byte[] PRGVRAM;      // PRG VRAM, for the alternative nametable arrangements.\n\n        public Cartridge(string filepath) // Constructor from file path\n        {\n            ROM = File.ReadAllBytes(filepath); // Reads the file from the provided file path, and stores every byte into an array.\n\n            // The iNES header isn't actually part of the physical cartridge.\n            // Rather, the values of the iNES header are manually added to provide extra information to emulators.\n            // Info such as \"what mapper chip\", \"how many CHR banks?\" and even \"how should we mirror the nametables?\" are part of this header.\n\n            MemoryMapper = (byte)(ROM[7] & 0xF0);   // Parsing the iNES header to determine what mapper chip this cartridge uses.\n            MemoryMapper |= (byte)(ROM[6] >> 4);    // The upper nybble of byte 6, bitwise OR with the upper nybble of byte 7.\n            SubMapper = (byte)((ROM[8] & 0xF0) >> 4);\n\n            PRG_Size = ROM[4];  // Parsing the iNES header to determine how many kb of PRG data exists on this cartridge.\n            CHR_Size = ROM[5];  // Parsing the iNES header to determine how many kb of CHR data exists on this cartridge.\n\n            PRG_SizeMinus1 = (byte)(PRG_Size - 1); // This value is occasionally used whenever a mapper has a fixed bank from the end of the PRG data, like address $E000 in the MMC3 chip.\n\n            UsingCHRRAM = CHR_Size == 0; // If CHR_Size == 0, this is using CHR RAM\n\n\n            PRGROM = new byte[PRG_Size * 0x4000]; // 0x4000 bytes of PRG ROM, multiplied by byte 4 of the iNES header.\n            CHRROM = new byte[CHR_Size * 0x2000]; // 0x2000 bytes of CHR ROM, multiplied by byte 5 of the iNES header.\n            CHRRAM = new byte[0x2000];            // CHR RAM always has 2 kibibytes\n\n            NametableHorizontalMirroring = ((ROM[6] & 1) == 0); // The style in which the nametable is mirrored is part of the iNES header.\n            AlternativeNametableArrangement = ((ROM[6] & 8) != 0); // Some mappers support other arrangements.\n            if (AlternativeNametableArrangement)\n            {\n                PRGVRAM = new byte[0x800];\n            }\n\n            Array.Copy(ROM, 0x10, PRGROM, 0, PRGROM.Length); // This sets up the PRG ROM array with the values from the .nes file\n            Array.Copy(ROM, 0x10 + PRGROM.Length, CHRROM, 0, CHRROM.Length); // This sets up the CHR ROM array with the values from the .nes file\n\n            // at this point, the ROM byte array is no longer needed, so null it to free up its memory.\n            ROM = null;\n\n            PRGRAM = new byte[0x2000]; // PRG RAM probably has different lengths depending on the mapper, but this emulator doesn't yet support any mappers in which that length isn't 2 kibibytes.\n\n            Name = filepath; // For debugging, it's nice to see the file name sometimes.\n\n            switch (MemoryMapper)\n            {\n                default:\n                case 0: MapperChip = new Mapper_NROM(); break;\n                case 1: MapperChip = new Mapper_MMC1(); break;\n                case 2: MapperChip = new Mapper_UxROM(); break;\n                case 3: MapperChip = new Mapper_CNROM(); break;\n                case 4: MapperChip = new Mapper_MMC3(); break;\n                case 7: MapperChip = new Mapper_AOROM(); break;\n                case 9: MapperChip = new Mapper_MMC2(); break;\n                case 69: MapperChip = new Mapper_FME7(); break;\n            }\n            MapperChip.Cart = this;\n        }\n        public DiskDrive FDS;   // The famicom disk system disk drive.\n        public Cartridge(string filepath, string FDSBIOS_filepath)\n        {\n            ROM = File.ReadAllBytes(FDSBIOS_filepath); // Reads the file from the provided file path, and stores every byte into an array.\n            FDS = new DiskDrive();\n            FDS.InsertDisk(filepath);\n            PRGRAM = new byte[0x8000]; // The FDS has 32Kib of PRG RAM!\n            CHRRAM = new byte[0x2000]; // and 8 Kib of CHR RAM.\n            Name = filepath; // For debugging, it's nice to see the file name sometimes.\n\n            MapperChip = new Mapper_FDS(ROM);\n            MapperChip.Cart = this;\n            FDS.Cart = this;\n        }\n\n        public bool NametableHorizontalMirroring;\n\n        public Mapper MapperChip;\n    }\n\n    public class Mapper\n    {\n        public Cartridge Cart;\n        public byte dataBus;\n        public byte observedDataBus;\n        public bool dataPinsAreNotFloating;\n        public bool observedDataPinsAreNotFloating;\n\n        // Default to NROM behavior.\n        public virtual void FetchPRG(ushort Address, bool Observe)\n        {\n            bool notFloating = false;\n            byte data = 0;\n            if (!Observe) { dataPinsAreNotFloating = false; } else { observedDataPinsAreNotFloating = false; }\n            // Observing can happen on a different thread, so we need to ensure that observing doesn't overwrite the data bus or floating pins status.\n\n            if (Address >= 0x8000)\n            {\n                data = Cart.PRGROM[Address & (Cart.PRGROM.Length - 1)]; // Get the address from the ROM file. If the ROM only has $4000 bytes, this will make addresses > $BFFF mirrors of $8000 through $BFFF.\n                notFloating = true;\n            }\n            //open bus\n\n            if (notFloating)\n            {\n                EndFetchPRG(Observe, data);\n            }\n            return;\n        }\n        public virtual void StorePRG(ushort Address, byte Input)\n        {\n        }\n        public virtual byte FetchCHR(ushort Address, bool Observe)\n        {\n            return Cart.CHRROM[Address & 0x1FFF];\n        }\n        public virtual byte FetchPPU()\n        {\n            // This will always use the upper 8 bits of the address bus | the octal latch. This replaces the lower 8 bits of the address bus.\n            ushort Address = (ushort)((Cart.Emu.PPU_AddressBus & 0x3F00) | Cart.Emu.PPU_OctalLatch);\n            bool CIRAM = Address >= 0x2000;\n            if (!CIRAM)\n            {\n                if (Cart.UsingCHRRAM)\n                {\n                    Cart.Emu.PPU_AddressBus &= 0xFF00;\n                    Cart.Emu.PPU_AddressBus |= Cart.CHRRAM[Address];\n                }\n                else\n                {\n                    //Pattern Table\n                    Cart.Emu.PPU_AddressBus &= 0xFF00;\n                    Cart.Emu.PPU_AddressBus |= Cart.MapperChip.FetchCHR(Address, false);\n                }\n            }\n            else // if the VRAM address is >= $2000, we need to consider nametable mirroring.\n            {\n                Address = MirrorNametable(Address);\n                Address &= 0x7FF;\n                Cart.Emu.PPU_AddressBus &= 0xFF00;\n                Cart.Emu.PPU_AddressBus |= Cart.Emu.VRAM[Address];                \n            }\n            return (byte)Cart.Emu.PPU_AddressBus;\n        }\n        public virtual ushort MirrorNametable(ushort Address)\n        {\n            if (!Cart.NametableHorizontalMirroring)\n            {\n                return (ushort)(Address & 0x37FF); // mask away $0800\n            }\n            else // horizontal\n            {\n                return (ushort)((Address & 0x33FF) | ((Address & 0x0800) >> 1)); // mask away $0C00, bit 10 becomes the former bit 11\n            }\n        }\n        public virtual List<byte> SaveMapperRegisters()\n        {\n            List<byte> State = new List<byte>();\n            foreach (Byte b in Cart.PRGRAM) { State.Add(b); }\n            foreach (Byte b in Cart.CHRRAM) { State.Add(b); }\n            return State;\n        }\n        public virtual void LoadMapperRegisters(List<byte> State, int startIndex, out int exitIndex)\n        {\n            int p = startIndex;\n            for (int i = 0; i < Cart.PRGRAM.Length; i++) { Cart.PRGRAM[i] = State[p++]; }\n            for (int i = 0; i < Cart.CHRRAM.Length; i++) { Cart.CHRRAM[i] = State[p++]; }\n            exitIndex = p;\n        }\n        public virtual void PPUClock() // runs every PPU clock. (See MMC3)\n        {\n        }\n        public virtual void CPUClock() // runs every CPU clock. (See Sunsoft FME-7)\n        {\n        }\n        public virtual void CPUClockRise() // runs every time the CPU clock rises. (See MMC3)\n        {\n        }\n\n        public virtual void FDS_ByteTransferFlag()\n        {\n        }\n        public virtual byte FDS_Get4025()\n        {\n            return 0;\n        }\n\n        protected void EndFetchPRG(bool Observe, byte data)\n        {\n            if (!Observe)\n            {\n                dataPinsAreNotFloating = true;\n                dataBus = data;\n            }\n            else\n            {\n                observedDataPinsAreNotFloating = true;\n                observedDataBus = data;\n            }\n        }\n    }\n\n    public class DiskDrive\n    {\n        public Cartridge Cart;\n        public byte[] Disk;\n        public byte ShiftRegister;\n        public byte ShiftRegisterLatch;\n        public bool IRQ;\n        public ushort clock; // every 1792 master clock cycles,\n\n        public ushort DiskAddress;\n        public byte DiskAddressFine;\n\n        public bool Status_ByteTransferFlag;\n\n        public void Clock()\n        {\n            clock++;\n            if(clock % 244 == 0)\n            {\n                if ((Cart.MapperChip.FDS_Get4025() & 0x46) == 0x44)\n                {\n                    // reading\n\n                    byte ShiftBit = (byte)((Disk[DiskAddress] << DiskAddressFine) & 1);\n                    ShiftRegister <<= 1;\n                    ShiftRegister |= ShiftBit;\n                    DiskAddressFine++;\n                    if (DiskAddressFine == 8)\n                    {\n                        DiskAddressFine = 0;\n                        DiskAddress++;\n                    }\n                }\n            }\n\n            if(clock == 1792)\n            {\n                clock = 0;\n                DiskAddressFine = 0;\n\n                ShiftRegisterLatch = ShiftRegister;\n                // disk drive is ready.\n                // raise the byte transfer flag!\n                Status_ByteTransferFlag = true;\n                Cart.MapperChip.FDS_ByteTransferFlag(); // Trigger an IRQ if $4025.7 is set.\n\n            }\n        }\n\n\n        public void InsertDisk(string filepath)\n        {\n            Disk = File.ReadAllBytes(filepath); // Reads the file from the provided file path, and stores every byte into an array.\n        }\n    }\n\n\n    public class Emulator\n    {\n\n        public Cartridge Cart;  // The idea behind this emulator is that this value could be changed at any time if you so desire.\n        public byte PPUClock;    // Counts down from 4. When it's 0, a PPU cycle occurs.\n        public byte CPUClock;    // Counts down from 12. When it's 0, a CPU cycle occurs.\n        public byte MasterClock; // Counts up every master clock cycle. Resets at 24.\n\n        public byte APUAlignment; // at power on or reset, is this a get/put, and how long until the DMC DMA?\n\n        public bool APU_PutCycle = false; // The APU needs to know if this is a \"get\" or \"put\" cycle.\n\n        public byte[] OAM = new byte[0x100];         // Object Attribute Memory is 256 bytes.\n        public byte[] OAM2 = new byte[32];   // Secondary OAM is specifically the 8 objects being rendered on the current scanline.\n        public byte SecondaryOAMSize = 0;            // This is a count of how many objects are currently in secondary OAM.\n        public byte OAM2Address = 0;         // During sprite evaluation, the current SecondaryOAM Address is used to track what byte is set of a given dot.\n        public bool SecondaryOAMFull = false;        // If full and another object exists in the same scanline, the PPU Sprite OVerflow flag is set.\n        public byte SpriteEvaluationTick = 0;        // During sprite evaluation, there's a switch statement that determines what to do on a given dot. This determines which action to take.\n        public bool OAMAddressOverflowedDuringSpriteEvaluation = false; // If the OAM address overflows during sprite evaluation, there's a few bugs that can occur.\n\n        public byte[] RAM = new byte[0x800];    // There are 0x800 bytes of RAM\n        public byte[] VRAM = new byte[0x800];   // There are 0x800 bytes of VRAM\n        public byte[] PaletteRAM = new byte[0x20]; // there are 0x20 bytes of palette RAM\n\n        public ushort programCounter = 0;   // The PC. What address is currently being executed?\n        public byte opCode = 0; // The first CPU cycle of an instruction will read the opcode. This determines how the rest of the cycles will behave.\n\n        public int totalCycles; // For debugging. This is just a count of how many CPU cycles have occurred since the console booted up.\n\n        public byte stackPointer = 0x00; // The Stack pointer is used during pushing/popping values with the stack. This determines which address will be read or written to.\n\n        public bool flag_Carry;      // The Carry flag is used in BCC and BCS instructions, and is set when the result of an operation over/underflows.\n        public bool flag_Zero;       // The Zero flag is used in BNE and BEQ instructions, and is set when the result of an operation is zero.\n        public bool flag_Interrupt;  // The Interrupt suppression flag will suppress IRQ's. \n        public bool flag_Decimal;    // The NES doesn't use this flag.\n        public bool flag_Overflow;   // The Carry flag is used in BVC and BVS instructions, and is set when the result of an operation over/underflows and the sign of the result is the same as the value before the operation.\n        public bool flag_Negative;   // The Zero flag is used in BPL and BMI instructions, and is set when the result of an operation is negative. (bit 7 is set)\n        byte status = 0;             // This is a byte representation of all the flags.\n        public byte A = 0;           // The Accumulator, or \"A Register\"\n        public byte X = 0;           // The X Register\n        public byte Y = 0;           // The Y Register\n        public byte H = 0;           // The High byte of the target address. A couple unofficial instructions use this value.\n        public bool IgnoreH;         // However, with a well-timed DMA, the H register isn't actually part of the equation on some of those.\n        public byte dataBus = 0;     // The Data Bus.\n        public byte internalBus = 0; // The Data Bus (internal to address $4015)\n\n        public ushort addressBus = 0;// The Address Bus. \"Where are we reading/writing\"\n        public byte specialBus = 0;  // The Special Bus is used in certain instructions. (The special bus is mostly used in half-CPU-cycles connecting the various registers to the alu)\n        public byte dl = 0;          // Data Latch. This holds values between CPU cycles that are used in later cycles within an instruction.\n\n\n        public byte operationCycle = 0; // This tracks what cycle of a given instruction is being emulated. Cycle 0 fetches the opcode, and all cycles after that have specific logic depending on which cycle needs emulated next.\n\n        public ushort temporaryAddress; // I use this to temporarily modify the value of the address bus for some if statements. This is mostly for checking if the low byte under/over flows.\n\n\n        public static uint[] NesPalInts = {\n            // each uint represents the ARGB components of a color.\n            // there's 64 colors, but this is also how I implement specific values for the PPU's emphasis bits.\n            // default palette:\n            0xFF656565, 0xFF002A84, 0xFF1513A2, 0xFF3A019E, 0xFF59007A, 0xFF6A003E, 0xFF680800, 0xFF531D00, 0xFF323400, 0xFF0D4600, 0xFF004F00, 0xFF004C09, 0xFF003F4B, 0xFF000000, 0xFF000000, 0xFF000000,\n            0xFFAEAEAE, 0xFF175FD6, 0xFF4341FF, 0xFF7529FA, 0xFF9E1DCA, 0xFFB4207B, 0xFFB13322, 0xFF964E00, 0xFF6A6C00, 0xFF398400, 0xFF0F9000, 0xFF008D33, 0xFF007B8C, 0xFF000000, 0xFF000000, 0xFF000000,\n            0xFFFEFFFF, 0xFF66AFFF, 0xFF9390FF, 0xFFC578FF, 0xFFEE6CFF, 0xFFFF6FCA, 0xFFFF8271, 0xFFE69E25, 0xFFBABC00, 0xFF88D501, 0xFF5EE132, 0xFF47DD82, 0xFF4ACBDC, 0xFF4E4E4E, 0xFF000000, 0xFF000000,\n            0xFFFEFFFF, 0xFFC0DEFF, 0xFFD2D1FF, 0xFFE7C7FF, 0xFFF8C2FF, 0xFFFFC3E9, 0xFFFFCBC4, 0xFFF5D7A5, 0xFFE2E394, 0xFFCEED96, 0xFFBCF2AA, 0xFFB3F1CB, 0xFFB4E9F0, 0xFFB6B6B6, 0xFF000000, 0xFF000000,\n            // emphasize red:\n            0xFF66423E, 0xFF000D58, 0xFF150075, 0xFF380075, 0xFF560058, 0xFF670027, 0xFF680000, 0xFF530D00, 0xFF341E00, 0xFF102B00, 0xFF003000, 0xFF002B00, 0xFF001C24, 0xFF000000, 0xFF000000, 0xFF000000,\n            0xFFAF7E78, 0xFF19379A, 0xFF4320C1, 0xFF720FC1, 0xFF9A089A, 0xFFB10F59, 0xFFB2220F, 0xFF963700, 0xFF6C4D00, 0xFF3D5F00, 0xFF166500, 0xFF005F0C, 0xFF004B55, 0xFF000000, 0xFF000000, 0xFF000000,\n            0xFFFFC0B8, 0xFF6878DB, 0xFF9361FF, 0xFFC24FFF, 0xFFEA49DB, 0xFFFF4F99, 0xFFFF634E, 0xFFE77808, 0xFFBC8F00, 0xFF8DA000, 0xFF65A708, 0xFF4DA04A, 0xFF4C8D95, 0xFF4F2F2B, 0xFF000000, 0xFF000000,\n            0xFFFFC0B8, 0xFFC1A2C6, 0xFFD399D6, 0xFFE792D6, 0xFFF78FC6, 0xFFFF92AB, 0xFFFF9A8C, 0xFFF6A26F, 0xFFE4AC5F, 0xFFD1B35F, 0xFFC0B66F, 0xFFB7B38B, 0xFFB6ABA9, 0xFFB7857E, 0xFF000000, 0xFF000000,\n            // emphasize green:\n            0xFF395D2C, 0xFF002452, 0xFF000D6A, 0xFF140064, 0xFF2D0041, 0xFF3E0010, 0xFF3F0300, 0xFF301800, 0xFF162F00, 0xFF004200, 0xFF004C00, 0xFF004700, 0xFF003924, 0xFF000000, 0xFF000000, 0xFF000000,\n            0xFF71A360, 0xFF005691, 0xFF1939B1, 0xFF4020A9, 0xFF61127B, 0xFF78183A, 0xFF792C00, 0xFF654800, 0xFF426600, 0xFF1B7E00, 0xFF008D00, 0xFF00860A, 0xFF007254, 0xFF000000, 0xFF000000, 0xFF000000,\n            0xFFAEF099, 0xFF32A3CB, 0xFF5684EB, 0xFF7E6BE3, 0xFF9E5DB5, 0xFFB66472, 0xFFB77728, 0xFFA39400, 0xFF7FB200, 0xFF57CB00, 0xFF37D900, 0xFF1FD342, 0xFF1EBF8D, 0xFF27471C, 0xFF000000, 0xFF000000,\n            0xFFAEF099, 0xFF7BD0AD, 0xFF8AC3BA, 0xFF9AB9B7, 0xFFA8B3A4, 0xFFB1B689, 0xFFB2BE6A, 0xFFAACA50, 0xFF9BD643, 0xFF8BE146, 0xFF7DE65A, 0xFF74E475, 0xFF73DC94, 0xFF77AA65, 0xFF000000, 0xFF000000,\n            // emphasize red + green:\n            0xFF3F3F25, 0xFF000B46, 0xFF00005D, 0xFF18005A, 0xFF2F003F, 0xFF40000E, 0xFF410000, 0xFF320A00, 0xFF191A00, 0xFF002800, 0xFF002F00, 0xFF002A00, 0xFF001B1C, 0xFF000000, 0xFF000000, 0xFF000000,\n            0xFF797A55, 0xFF003581, 0xFF201F9F, 0xFF450D9C, 0xFF640478, 0xFF7B0A36, 0xFF7C1E00, 0xFF683200, 0xFF474900, 0xFF225B00, 0xFF036400, 0xFF005D00, 0xFF004A4A, 0xFF000000, 0xFF000000, 0xFF000000,\n            0xFFBABB8B, 0xFF3E75B7, 0xFF605ED6, 0xFF854CD2, 0xFFA443AE, 0xFFBB4A6C, 0xFFBD5D21, 0xFFA87200, 0xFF878900, 0xFF619B00, 0xFF42A400, 0xFF2B9D34, 0xFF2A8A7F, 0xFF2C2D15, 0xFF000000, 0xFF000000,\n            0xFFBABB8B, 0xFF879E9D, 0xFF9595AA, 0xFFA48DA8, 0xFFB18999, 0xFFBB8C7E, 0xFFBB945F, 0xFFB39D48, 0xFFA5A63B, 0xFF96AE3D, 0xFF89B14C, 0xFF7FAF67, 0xFF7FA686, 0xFF80805A, 0xFF000000, 0xFF000000,\n            // emphasize blue:\n            0xFF47477C, 0xFF001A8C, 0xFF0B0AA9, 0xFF2900A3, 0xFF410081, 0xFF4D004A, 0xFF49000D, 0xFF340400, 0xFF141500, 0xFF002800, 0xFF003300, 0xFF00331B, 0xFF002A58, 0xFF000000, 0xFF00000A, 0xFF00000A,\n            0xFF8584CD, 0xFF0B49E2, 0xFF3533FF, 0xFF5D1AFF, 0xFF7D0CD4, 0xFF8D0B8B, 0xFF86173A, 0xFF6B2C00, 0xFF414200, 0xFF195B00, 0xFF006904, 0xFF006A4C, 0xFF005E9E, 0xFF00000A, 0xFF00000A, 0xFF00000A,\n            0xFFC9C8FF, 0xFF4E8CFF, 0xFF7876FF, 0xFFA05CFF, 0xFFC14EFF, 0xFFD14DE4, 0xFFCB5A92, 0xFFAF6E4C, 0xFF848525, 0xFF5C9E2D, 0xFF3BAD5B, 0xFF2BADA5, 0xFF32A1F7, 0xFF343362, 0xFF00000A, 0xFF00000A,\n            0xFFC9C8FF, 0xFF96AFFF, 0xFFA8A6FF, 0xFFB89BFF, 0xFFC696FF, 0xFFCC95FF, 0xFFCA9AEA, 0xFFBEA3CD, 0xFFACACBD, 0xFF9CB7C0, 0xFF8FBDD3, 0xFF88BDF2, 0xFF8BB8FF, 0xFF8B8AD6, 0xFF00000A, 0xFF00000A,\n            // emphasize red + blue:\n            0xFF46344C, 0xFF00085C, 0xFF0B007A, 0xFF260077, 0xFF3D005C, 0xFF4A0030, 0xFF480000, 0xFF340000, 0xFF140F00, 0xFF001D00, 0xFF002400, 0xFF002200, 0xFF001829, 0xFF000000, 0xFF000000, 0xFF000000,\n            0xFF846B8C, 0xFF0A30A1, 0xFF3419C8, 0xFF5907C5, 0xFF7800A1, 0xFF880166, 0xFF860E23, 0xFF6B2300, 0xFF403900, 0xFF1C4C00, 0xFF005400, 0xFF00521A, 0xFF00445C, 0xFF000000, 0xFF000000, 0xFF000000,\n            0xFFC7A7D2, 0xFF4C6BE8, 0xFF7754FF, 0xFF9C42FF, 0xFFBB39E7, 0xFFCC3CAB, 0xFFCA4968, 0xFFAE5E23, 0xFF837500, 0xFF5E8700, 0xFF3F9023, 0xFF2E8E5F, 0xFF3080A2, 0xFF332338, 0xFF000000, 0xFF000000,\n            0xFFC7A7D2, 0xFF948EDB, 0xFFA685EB, 0xFFB57DEA, 0xFFC27ADB, 0xFFC97BC2, 0xFFC880A7, 0xFFBD898A, 0xFFAB927A, 0xFF9C9A7B, 0xFF8F9D8A, 0xFF889CA3, 0xFF8997BE, 0xFF8A7093, 0xFF000000, 0xFF000000,\n            // emphasize green + blue:\n            0xFF304144, 0xFF00155A, 0xFF000471, 0xFF11006B, 0xFF2A0049, 0xFF36001C, 0xFF350000, 0xFF250300, 0xFF0C1300, 0xFF002600, 0xFF003100, 0xFF002F00, 0xFF002531, 0xFF000000, 0xFF000000, 0xFF000000,\n            0xFF647D80, 0xFF00429E, 0xFF152CBC, 0xFF3C13B4, 0xFF5C0586, 0xFF6D074B, 0xFF6B1509, 0xFF572900, 0xFF364000, 0xFF0E5900, 0xFF006700, 0xFF006424, 0xFF005766, 0xFF000000, 0xFF000000, 0xFF000000,\n            0xFF9EBEC3, 0xFF2D83E1, 0xFF4E6CFF, 0xFF7653F8, 0xFF9745C9, 0xFFA7478D, 0xFFA5554A, 0xFF916A12, 0xFF6F8100, 0xFF479A00, 0xFF27A82A, 0xFF16A566, 0xFF1898A9, 0xFF1F2E30, 0xFF000000, 0xFF000000,\n            0xFF9EBEC3, 0xFF6FA6CF, 0xFF7D9CDC, 0xFF8E92D8, 0xFF9B8CC5, 0xFFA28DAD, 0xFFA19391, 0xFF999C7A, 0xFF8BA56D, 0xFF7AAF70, 0xFF6DB584, 0xFF66B49C, 0xFF67AEB8, 0xFF6A8386, 0xFF000000, 0xFF000000,\n            // emphasize red + green + blue:\n            0xFF343434, 0xFF00084B, 0xFF000061, 0xFF14005F, 0xFF2B0044, 0xFF380017, 0xFF360000, 0xFF270000, 0xFF0E0F00, 0xFF001D00, 0xFF002400, 0xFF002200, 0xFF001721, 0xFF000000, 0xFF000000, 0xFF000000,\n            0xFF6A6A6A, 0xFF003088, 0xFF1B19A7, 0xFF4007A3, 0xFF5F007F, 0xFF6F0144, 0xFF6D0E02, 0xFF592300, 0xFF383900, 0xFF134B00, 0xFF005400, 0xFF00520F, 0xFF004451, 0xFF000000, 0xFF000000, 0xFF000000,\n            0xFFA6A6A6, 0xFF356BC5, 0xFF5654E3, 0xFF7B42E0, 0xFF9B39BB, 0xFFAB3C80, 0xFFA9493D, 0xFF955E04, 0xFF737500, 0xFF4E8700, 0xFF2F900E, 0xFF1E8E4A, 0xFF20808D, 0xFF232323, 0xFF000000, 0xFF000000,\n            0xFFA6A6A6, 0xFF788EB3, 0xFF8585C0, 0xFF957DBE, 0xFFA279AF, 0xFFA87A96, 0xFFA8807B, 0xFF9F8964, 0xFF919257, 0xFF829A59, 0xFF759D68, 0xFF6E9C80, 0xFF6F979C, 0xFF707070, 0xFF000000, 0xFF000000,\n            // colorburst\n            0xFF010900\n        };\n\n        int chosenColor; // During screen rendering, this value is the index into the color array.\n        public DirectBitmap Screen = new DirectBitmap(256, 240); // This uses a class called \"DirectBitmap\". It's pretty much just the same as Bitmap, but I don't need to unlock/lock the bits, so it's faster.\n        public DirectBitmap NTSCScreen = new DirectBitmap(256 * 8, 240); // This uses a class called \"DirectBitmap\". It's pretty much just the same as Bitmap, but I don't need to unlock/lock the bits, so it's faster.\n        public DirectBitmap BorderedScreen = new DirectBitmap(341, 262); // This uses a class called \"DirectBitmap\". It's pretty much just the same as Bitmap, but I don't need to unlock/lock the bits, so it's faster.\n        public DirectBitmap BorderedNTSCScreen = new DirectBitmap(341 * 8, 262); // This uses a class called \"DirectBitmap\". It's pretty much just the same as Bitmap, but I don't need to unlock/lock the bits, so it's faster.\n\n        //Debugging\n        public bool Logging;    // If set, the tracelogger will record all instructions ran.\n        public bool LoggingPPU;\n        public StringBuilder DebugLog; // This is where the tracelogger is recording.\n\n        public Emulator() // The instantiator for this class\n        {\n            RAM = new byte[0x800];\n            A = 0;  // The A, X, and Y registers are all initialized with 0 when the console boots up.\n            X = 0;\n            Y = 0;\n            VRAM = new byte[0x800];\n            OAM = new byte[0x100];\n            OAM2 = new byte[32];\n            for (int oam2_init = 0; oam2_init < OAM2.Length; oam2_init++)\n            {\n                OAM2[oam2_init] = 0xFF;\n            }\n\n            // set up RAM and PPU RAM Pattern\n            int i = 0;\n            while (i < 0x800)\n            {\n                int j = i & 0x2;\n                bool swap = (i & 0x1F) >= 0x10;\n                if (j < 0x2 == !swap)\n                {\n                    VRAM[i] = 0xF0;\n                    RAM[i] = 0xF0;\n                }\n                else\n                {\n                    VRAM[i] = 0x0F;\n                    RAM[i] = 0x0F;\n                }\n                i++;\n            }\n\n            bool BlarggPalette = false; // There's a PPU test cartridge that expects a very specific palette when you power on the console.\n            if (BlarggPalette)\n            {\n                //use the palette that Blargg's NES uses\n                PaletteRAM[0x00] = 0x09;\n                PaletteRAM[0x01] = 0x01;\n                PaletteRAM[0x02] = 0x00;\n                PaletteRAM[0x03] = 0x01;\n                PaletteRAM[0x04] = 0x00;\n                PaletteRAM[0x05] = 0x02;\n                PaletteRAM[0x06] = 0x02;\n                PaletteRAM[0x07] = 0x0D;\n                PaletteRAM[0x08] = 0x08;\n                PaletteRAM[0x09] = 0x10;\n                PaletteRAM[0x0A] = 0x08;\n                PaletteRAM[0x0B] = 0x24;\n                PaletteRAM[0x0C] = 0x00;\n                PaletteRAM[0x0D] = 0x00;\n                PaletteRAM[0x0E] = 0x04;\n                PaletteRAM[0x0F] = 0x2C;\n                PaletteRAM[0x10] = 0x09;\n                PaletteRAM[0x11] = 0x01;\n                PaletteRAM[0x12] = 0x34;\n                PaletteRAM[0x13] = 0x03;\n                PaletteRAM[0x14] = 0x00;\n                PaletteRAM[0x15] = 0x04;\n                PaletteRAM[0x16] = 0x00;\n                PaletteRAM[0x17] = 0x14;\n                PaletteRAM[0x18] = 0x08;\n                PaletteRAM[0x19] = 0x3A;\n                PaletteRAM[0x1A] = 0x00;\n                PaletteRAM[0x1B] = 0x02;\n                PaletteRAM[0x1C] = 0x00;\n                PaletteRAM[0x1D] = 0x20;\n                PaletteRAM[0x1E] = 0x2C;\n                PaletteRAM[0x1F] = 0x08;\n            }\n            else // Except my actual console has a different palette than Blargg, so I use this palette instead.\n            {\n                // use the palette that my NES uses\n                PaletteRAM[0x00] = 0x00;\n                PaletteRAM[0x01] = 0x00;\n                PaletteRAM[0x02] = 0x28;\n                PaletteRAM[0x03] = 0x00;\n                PaletteRAM[0x04] = 0x00;\n                PaletteRAM[0x05] = 0x08;\n                PaletteRAM[0x06] = 0x00;\n                PaletteRAM[0x07] = 0x00;\n                PaletteRAM[0x08] = 0x00;\n                PaletteRAM[0x09] = 0x01;\n                PaletteRAM[0x0A] = 0x01;\n                PaletteRAM[0x0B] = 0x20;\n                PaletteRAM[0x0C] = 0x00;\n                PaletteRAM[0x0D] = 0x08;\n                PaletteRAM[0x0E] = 0x00;\n                PaletteRAM[0x0F] = 0x02;\n                PaletteRAM[0x10] = 0x00;\n                PaletteRAM[0x11] = 0x00;\n                PaletteRAM[0x12] = 0x00;\n                PaletteRAM[0x13] = 0x00;\n                PaletteRAM[0x14] = 0x00;\n                PaletteRAM[0x15] = 0x02;\n                PaletteRAM[0x16] = 0x21;\n                PaletteRAM[0x17] = 0x00;\n                PaletteRAM[0x18] = 0x00;\n                PaletteRAM[0x19] = 0x00;\n                PaletteRAM[0x1A] = 0x00;\n                PaletteRAM[0x1B] = 0x00;\n                PaletteRAM[0x1C] = 0x00;\n                PaletteRAM[0x1D] = 0x10;\n                PaletteRAM[0x1E] = 0x00;\n                PaletteRAM[0x1F] = 0x00;\n            }\n\n            programCounter = 0xFFFF; // Technically, this value is nondeterministic. It also doesn't matter where it is, as it will be initialized in the RESET instruction.\n            PPU_Scanline = 0;        // The PPU begins on dot 0 of scanline 0\n            PPU_Dot = 7;       // Shouldn't this be 0? I don't know why, but this passes all the tests if this is 7, so...?\n\n            PPU_OddFrame = true;    // And this is technically considered an \"odd\" frame when it comes to even/odd frame timing.\n\n            APU_DMC_SampleAddress = 0xC000;\n            APU_DMC_AddressCounter = 0xC000;\n\n            APU_DMC_SampleLength = 1;\n            APU_DMC_ShifterBitsRemaining = 8;\n\n            switch (APUAlignment & 4)\n            {\n                default:\n                case 0:\n                    {\n                        APU_ChannelTimer_DMC = 1022;\n                        APU_PutCycle = true;\n                    }\n                    break;\n                case 1:\n                    {\n                        APU_ChannelTimer_DMC = 1022;\n                        APU_PutCycle = false;\n                    }\n                    break;\n                case 2:\n                    {\n                        APU_ChannelTimer_DMC = 1020;\n                        APU_PutCycle = true;\n                    }\n                    break;\n                case 3:\n                    {\n                        APU_ChannelTimer_DMC = 1020;\n                        APU_PutCycle = false;\n                    }\n                    break;\n            }\n\n            DoReset = true; // This is used to force the first instruction at power on to be the RESET instruction.\n            PPU_RESET = false; // I'm not even 100% certain my console has this behavior. I'll set it to false for now.\n        }\n\n        public bool PPU_RESET;\n\n        // when pressing the reset button, this function runs\n        public void Reset()\n        {\n            // The A, X, and Y registers are unchanged through reset.\n            // most flags go unchanged as well, but the I flag is set to 1\n            flag_Interrupt = true;\n            // Triangle phase gets reset, though I'm not yet emulating audio.\n            APU_DMC_Output &= 1;\n            // All the bits of $4015 are cleared\n            APU_Status_DMCInterrupt = false;\n            APU_Status_FrameInterrupt = false;\n            APU_Status_DelayedDMC = false;\n            APU_Status_DMC = false;\n            APU_Status_Noise = false;\n            APU_Status_Triangle = false;\n            APU_Status_Pulse2 = false;\n            APU_Status_Pulse1 = false;\n            APU_DMC_BytesRemaining = 0;\n            APU_LengthCounter_Noise = 0;\n            APU_LengthCounter_Triangle = 0;\n            APU_LengthCounter_Pulse2 = 0;\n            APU_LengthCounter_Pulse1 = 0;\n            APU_Framecounter = 0; // reset the frame counter\n\n            // PPU registers\n            PPUControl_NMIEnabled = false;\n            PPUControlIncrementMode32 = false;\n            PPU_Spritex16 = false;\n            PPU_PatternSelect_Sprites = false;\n            PPU_PatternSelect_Background = false;\n            PPU_t = 0;\n\n            PPU_Mask_Greyscale = false;\n            PPU_Mask_EmphasizeRed = false;\n            PPU_Mask_EmphasizeGreen = false;\n            PPU_Mask_EmphasizeBlue = false;\n            PPU_Mask_8PxShowBackground = false;\n            PPU_Mask_8PxShowSprites = false;\n            PPU_Mask_ShowBackground = false;\n            PPU_Mask_ShowSprites = false;\n\n            PPU_Update2005Delay = 0;\n            PPU_FineXScroll = 0;\n\n            //$2006 is unchanged\n\n            PPU_ReadBuffer = 0;\n            PPU_OddFrame = false;\n\n            PPU_Dot = 0;\n            PPU_Scanline = 0;\n\n            DoDMCDMA = false;\n            DoOAMDMA = false;\n            operationCycle = 0;\n\n            switch (APUAlignment & 4)\n            {\n                default:\n                case 0:\n                    {\n                        APU_ChannelTimer_DMC = 1022;\n                        APU_PutCycle = true;\n                    }\n                    break;\n                case 1:\n                    {\n                        APU_ChannelTimer_DMC = 1022;\n                        APU_PutCycle = false;\n                    }\n                    break;\n                case 2:\n                    {\n                        APU_ChannelTimer_DMC = 1020;\n                        APU_PutCycle = true;\n                    }\n                    break;\n                case 3:\n                    {\n                        APU_ChannelTimer_DMC = 1020;\n                        APU_PutCycle = false;\n                    }\n                    break;\n            }\n\n            DoReset = true;\n            PPU_RESET = false; // I'm not even 100% certain my console has this behavior. I'll set it to false for now.\n            // in theory, the CPU/PPU clock would be given random values. Let's just assume no changes.\n        }\n\n        public bool CPU_Read; // DMC DMA Has some specific behavior depending on if the CPU is currently reading or writing. DMA Halting fails / DMA $2007 bug.\n\n\n        // The BRK instruction is reused in the IRQ, NMI, and RESET logic. These bools are used both to start the instruction, and also to make sure the correct logic is used.\n        public bool DoBRK; // Set if the opcode is 00\n        public bool DoNMI; // Set if a Non Maskable Interrupt is occurring\n        public bool DoIRQ; // Set if an Interrupt Request is occurring\n\n        public bool DoReset;  // Set when resetting the console, or power on.\n        public bool DoOAMDMA; // If set, the Object Acctribute Memory's Direct Memory Access will occur.\n        public bool FirstCycleOfOAMDMA; // The first cycle caa behave differently.\n        public bool DoDMCDMA; // If set, the Delta Modulation Channel's Direct Memory Access will occur.\n        public byte DMCDMADelay; // There's actually a slight delay between the audio chip preparing the DMA, and the CPU actually running it.\n        public byte CannotRunDMCDMARightNow = 0;\n\n        public byte DMAPage;    // When running an OAM DMA, this is used to determine which \"page\" to read bytes from. Typically, this is page 2 (address $200 through $2FF)\n        public byte DMAAddress; // While this DMA runs, this value is incremented until it overflows.\n\n        public bool FrameAdvance_ReachedVBlank; // For debugging. If frame advancing, this is set when VBlank occurs.\n\n        public bool APU_ControllerPortsStrobing; // Set to true/false depending on the value written to $4016. When true, the buttons pressed are recorded in the shift registers.\n        public bool APU_ControllerPortsStrobed;  // This bool prevents strobing from rushing through the TAS input log.\n                                                 // This gets set to false if the controllers are unstrobed, or if the controller ports are read.\n\n        public byte ControllerPort1;            // The buttons currently pressed on controller 1. These are in the \"A, B, Select, Start, Up, Down, Left, Right\" order.\n        public byte ControllerPort2;            // The buttons currently pressed on controller 2. These are in the \"A, B, Select, Start, Up, Down, Left, Right\" order.\n        public byte ControllerShiftRegister1;   // Controllers are read 1 bit at a time. First the A Button is read, then B, and so on.\n        public byte ControllerShiftRegister2;   // Whenever the shift register is read, all the bits are shifted to the left, and a '1' replaces bit 0.\n        public byte Controller1ShiftCounter;    // Subsequent CPU cycles reading from $4016 do not update the shift register.\n        public byte Controller2ShiftCounter;    // Subsequent CPU cycles reading from $4017 do not update the shift register.\n\n        public bool LagFrame; // True if the controller port was not strobed in a frame.\n        public bool TASTimelineClockFiltering; // Primarily used in the TASTimeline if you are using subframe Inputs.\n\n        public void _CoreFrameAdvance()\n        {\n            // If we're running this emulator 1 frame at a time, this waits until VBlank and then returns.\n            FrameAdvance_ReachedVBlank = false;\n            LagFrame = true; // Many emulators detect \"lag frames\" by checking if the controller ports were strobed during this frame.\n            while (!FrameAdvance_ReachedVBlank)\n            {\n                _EmulatorCore();\n            }\n        }\n\n        public int CycleCountForCycleTAS = 0; // If we're running a intercycle cart swapping TAS, we need to keep track of which cycle we're on.\n        public void _CoreCycleAdvance()\n        {\n            // this runs 12 master clock cycles, or 1 CPU cycle.\n            int i = 0;\n            while (i < 12)\n            {\n                _EmulatorCore();\n                i++;\n            }\n            CycleCountForCycleTAS++;\n        }\n\n        public void _EmulatorCore()\n        {\n            // counters count down to 0, run the appropriate chip's logic, and the counter is reset.\n            // If multiple counters read 0 at the same time, there's an order of events.\n            // The order of events:\n            // CPU\n            // PPU\n            // APU\n\n            if (CPUClock == 12)\n            {\n                CPUClock = 0; // there is 1 CPU cycle for every 12 master clock cycles\n\n                _6502(); // This is where I run the CPU\n                totalCycles++;         // for debugging mostly\n                Cart.MapperChip.CPUClock(); // If the mapper chip does every cpu cycle... (see FME-7)\n            }\n            if (CPUClock == 4)\n            {\n                NMILine |= PPUControl_NMIEnabled && PPUStatus_VBlank;\n                if (operationCycle == 0 && !(PPUStatus_VBlank && PPUControl_NMIEnabled))\n                {\n                    NMILine = false;\n                }\n            }\n            if (CPUClock == 7) //M2 going low.\n            {\n                IRQLine = IRQ_LevelDetector;\n                if (APU_Status_FrameInterrupt && !APU_FrameCounterInhibitIRQ)\n                {\n                    IRQ_LevelDetector = true; // if the APU frame counter flag is never cleared, you will get another IRQ when the I flag is cleared.\n                }\n                Cart.MapperChip.CPUClockRise(); // If the mapper chip does something when M2 rises... (see MMC3)\n            }\n            if (PPUClock == 4)\n            {\n                PPUClock = 0; // there is 1 PPU cycle for every 12 master clock cycles\n\n                _EmulatePPU();\n                if (PPUBus != 0)\n                {\n                    DecayPPUDataBus();\n                }\n            }\n            if (PPUClock == 2)\n            {\n                _EmulateHalfPPU();\n            }\n            \n\n            if (CPUClock == 0)\n            {\n\n                _EmulateAPU();\n                APU_PutCycle = !APU_PutCycle;\n\n                // the APU is actually clocked every 24 master clock cycles.\n                // yet there's a lot of timing that happens every cpu cycle anyway??\n                // If the timing needs to be exactly n and a half APU cycles, then I'll just multiply the numbers by 2 and clock this twice as fast.\n            }\n\n            // Decrement the clocks.\n            PPUClock++;\n            CPUClock++;\n\n            if(Cart.FDS != null)\n            {\n                Cart.FDS.Clock();\n            }\n        }\n\n        public void EmulateUntilEndOfRead()\n        {\n            // this is used during reads from some ppu registers.\n            // run 1.75 ppu cycles. (the actual duty cycle here would result in 1 and 7/8 ppu cycles, but my emulator doesn't worry about half-master-clock-cycles.\n            for (int i = 0; i < 7; i++)\n            {\n                _EmulatorCore();\n            }\n        }\n\n        public void EmulateNMasterClockCycles(int n)\n        {\n            // This does run the risk of recursion, so don't use a value of 12 or more with this.\n            for (int i = 0; i < n; i++)\n            {\n                _EmulatorCore();\n            }\n        }\n\n        // Audio Processing Unit Variables //\n\n        // APU Status is at address $4015\n        public bool APU_Status_DMCInterrupt;  // Bit 7 of $4015\n        public bool APU_Status_FrameInterrupt;// Bit 6 of $4015\n        public bool APU_Status_DMC;           // Bit 5 of $4015\n        public bool APU_Status_DelayedDMC;    // Bit 5 of $4015, but with a slight delay.\n        public bool APU_Status_Noise;         // Bit 3 of $4015\n        public bool APU_Status_Triangle;      // Bit 2 of $4015\n        public bool APU_Status_Pulse2;        // Bit 1 of $4015\n        public bool APU_Status_Pulse1;        // Bit 0 of $4015\n\n        public bool Clearing_APU_FrameInterrupt;\n\n\n        public byte APU_DelayedDMC4015;         // When writing to $4015, there's a 3 or 4 cycle delay between the APU actually changing this value.\n        public bool APU_ImplicitAbortDMC4015;   // An edge case of the DMC DMA, where regardless of the buffer being empty, there will be a 1-cycle DMA that gets aborted 2 cycles after the load DMA ends\n        public bool APU_SetImplicitAbortDMC4015;// This is used to make that happen.\n\n        public byte[] APU_Register = new byte[0x10]; // Instead of making a series of variables, I made an array here for some reason.\n\n        public bool APU_FrameCounterMode;       // Bit 7 of $4017 : Determines if the APU frame counter is using the 4 step or 5 step modes.\n        public bool APU_FrameCounterInhibitIRQ; // Bit 6 of $4017 : If set, prevents the APU from creating IRQ's\n\n        public byte APU_FrameCounterReset = 0xFF; // When resetting the APU Frame counter by writing to address $4017, there's a 3 (or 4) CPU cycle delay. (3 if it's an even cpu cycle, 4 if odd.)\n        public ushort APU_Framecounter = 0;       // Increments every APU cycle. Since there are events that happen at half-step intervals, I actually increment this every CPU cycle and multiplied all intervals by 2.\n        public bool APU_QuarterFrameClock = false;// This is clocked approximately 4 times a frame, depending on the frame counter mode.\n        public bool APU_HalfFrameClock = false;   // This is clocked approximately twice a frame, depending on the frame counter mode.\n\n        public bool APU_Envelope_StartFlag = false;\n        public bool APU_Envelope_DividerClock = false;\n        public byte APU_Envelope_DecayLevel = 0;\n\n        public byte APU_LengthCounter_Pulse1 = 0;   // The length counter for the APU's Pulse 1 channel.\n        public byte APU_LengthCounter_Pulse2 = 0;   // The length counter for the APU's Pulse 2 channel.\n        public byte APU_LengthCounter_Triangle = 0; // The length counter for the APU's Triangle channel.\n        public byte APU_LengthCounter_Noise = 0;    // The length counter for the APU's Noise channel.\n\n        // When a length counter's reloaded value is set by writing to $4003, $4007, $400B, or $400F, this LookUp Table is used to determine the length based on the value written.\n        public static readonly byte[] APU_LengthCounterLUT = { 10, 254, 20, 2, 40, 4, 80, 6, 160, 8, 60, 10, 14, 12, 26, 14, 12, 16, 24, 18, 48, 20, 96, 22, 192, 24, 72, 26, 16, 28, 32, 30 };\n\n        public bool APU_LengthCounter_HaltPulse1 = false;   // set if Bit 5 of $4000 is 1\n        public bool APU_LengthCounter_HaltPulse2 = false;   // set if Bit 5 of $4004 is 1\n        public bool APU_LengthCounter_HaltTriangle = false; // set if Bit 7 of $4008 is 1\n        public bool APU_LengthCounter_HaltNoise = false;    // set if Bit 5 of $400C is 1\n\n        public bool APU_LengthCounter_ReloadPulse1 = false;  // When writing to $4003 (if the pulse 1 channel is enabled) this is set to true. The value is reloaded in the next APU cycle.\n        public bool APU_LengthCounter_ReloadPulse2 = false;  // When writing to $4007 (if the pulse 2 channel is enabled) this is set to true. The value is reloaded in the next APU cycle.\n        public bool APU_LengthCounter_ReloadTriangle = false;// When writing to $400B (if the triangle channel is enabled) this is set to true. The value is reloaded in the next APU cycle.\n        public bool APU_LengthCounter_ReloadNoise = false;   // When writing to $400F (if the noise channel is enabled) this is set to true. The value is reloaded in the next APU cycle.\n\n        public byte APU_LengthCounter_ReloadValuePulse1 = 0;  // When the pulse 1 channel is reloaded, the length counter will be set to this value. Modified by writing to $4003.\n        public byte APU_LengthCounter_ReloadValuePulse2 = 0;  // When the pulse 2 channel is reloaded, the length counter will be set to this value. Modified by writing to $4007.\n        public byte APU_LengthCounter_ReloadValueTriangle = 0;// When the triangle channel is reloaded, the length counter will be set to this value. Modified by writing to $400B.\n        public byte APU_LengthCounter_ReloadValueNoise = 0;   // When the noise channel is reloaded, the length counter will be set to this value. Modified by writing to $400F.\n\n        public ushort APU_ChannelTimer_Pulse1 = 0;  // Decrements every \"get\" cycle.\n        public ushort APU_ChannelTimer_Pulse2 = 0;  // Decrements every \"get\" cycle.\n        public ushort APU_ChannelTimer_Triangle = 0;// Decrements every CPU cycle.\n        public ushort APU_ChannelTimer_Noise = 0;   // Decrements every \"get\" cycle.\n        public ushort APU_ChannelTimer_DMC = 0;     // Decrements every CPU cycle.\n\n\n        // $4010\n        public bool APU_DMC_EnableIRQ = false;  // Will the DMC create IRQ's? Set by writing to address $4010\n        public bool APU_DMC_Loop = false;       // Will DPCM samples loop?\n        public ushort APU_DMC_Rate = 428;       // The default sample rate is the slowest.\n        // LookUp Table for how many CPU cycles are between each bit of the DPCM sample being played. (8 bits per byte, so to calculate how many cycles there are between each DMA, multiply these numbers by 8)\n        public static readonly ushort[] APU_DMCRateLUT = { 428, 380, 340, 320, 286, 254, 226, 214, 190, 160, 142, 128, 106, 84, 72, 54 };\n\n        // $4011 (and DPCM stuff)\n        public byte APU_DMC_Output; // Directly writing here (Address $4011) will set the DMC output. This is how you play PCM audio.\n\n        // $4012\n        public ushort APU_DMC_SampleAddress = 0xC000;   // Where the DPCM sample is being read from.\n\n        // $4013\n        public ushort APU_DMC_SampleLength = 0;  // How many bytes are being played in this DPCM sample? (multiplied by 64, and add 1)\n\n        public ushort APU_DMC_BytesRemaining = 0; // How many bytes are left in the sample. When a sample starts or loops, this is set to APU_DMC_SampleLength.\n        public byte APU_DMC_Buffer = 0;  // The value that goes into the shift register.\n        public ushort APU_DMC_AddressCounter = 0xC000; // What byte is fetched in the next DMA for DPCM audio? When a sample starts or loops, this is set to APU_DMC_SampleAddress.\n        public byte APU_DMC_Shifter = 0; // The 8 bits of the sample that were fetched from the DMA.\n        public byte APU_DMC_ShifterBitsRemaining = 8; // This tracks how many bits are left before needing to run another DMA\n        public bool DPCM_Up;    // If the next bit of the DPCM sample is a 1, the output goes up. Otherwise it goes down.\n\n        public bool APU_Silent = true;  // If the APU is not making any noise, this is set.\n\n        void _EmulateAPU()\n        {\n            // This runs every 12 master clock cycles, though has different logic for even/odd CPU cycles.\n            if (!APU_ControllerPortsStrobing)\n            {\n                if (Controller1ShiftCounter > 0)\n                {\n                    Controller1ShiftCounter--;\n                    if (Controller1ShiftCounter == 0)\n                    {\n                        ControllerShiftRegister1 <<= 1;\n                        ControllerShiftRegister1 |= 1;\n                    }\n                }\n                if (Controller2ShiftCounter > 0)\n                {\n                    Controller2ShiftCounter--;\n                    if (Controller2ShiftCounter == 0)\n                    {\n                        ControllerShiftRegister2 <<= 1;\n                        ControllerShiftRegister2 |= 1;\n                    }\n                }\n            }\n            else\n            {\n                Controller1ShiftCounter = 0;\n                Controller2ShiftCounter = 0;\n            }\n\n            if (!APU_PutCycle)\n            {\n                // If this is a get cycle, transitioning to a put cycle.\n\n                // controller reading is handled here in the APU chip.\n\n                // If a 1 was written to $4016, we are strobing the controller.\n                if (APU_ControllerPortsStrobing)\n                {\n                    if (!APU_ControllerPortsStrobed)\n                    {\n                        LagFrame = false;\n                        APU_ControllerPortsStrobed = true;\n                        if (TASTimelineClockFiltering)\n                        {\n                            FrameAdvance_ReachedVBlank = true; // Obviously this isn't actually VBlank, but we want to stop emulating here anyway.\n                        }\n                        // this will be reset to false if:\n                        // 1.) the controllers are un-strobed. Ready for the next strobe.\n                        // 2.) the controller ports are read, while still strobed. This allows data to be streamed in through the A button.\n\n                        if (TAS_ReadingTAS) // This is specifically how I load inputs from a TAS, and has nothing to do with actual NES behavior.\n                        {\n                            if (TAS_InputSequenceIndex < TAS_InputLog.Length)\n                            {\n                                ControllerPort1 = (byte)(TAS_InputLog[TAS_InputSequenceIndex] & 0xFF);\n                                ControllerPort2 = (byte)((TAS_InputLog[TAS_InputSequenceIndex] & 0xFF00) >> 8);\n                            }\n                            else // if the TAS has ended, only provide 0 as the inputs.\n                            {\n                                ControllerPort1 = 0;\n                                ControllerPort2 = 0;\n                            }\n                            if (ClockFiltering)\n                            {\n                                if (TAS_InputSequenceIndex > 0 && TAS_InputSequenceIndex < TAS_ResetLog.Length && TAS_ResetLog[TAS_InputSequenceIndex])\n                                {\n                                    Reset();\n                                }\n                                TAS_InputSequenceIndex++; // Instead of using 1 input per frame, this just advances to the next input\n                            }\n\n                        }\n                        // this sets up the shift registers with the value of the controller ports.\n                        // If not set by the TAS, these are probably set outside this script in the script for the form.\n                        ControllerShiftRegister1 = ControllerPort1;\n                        ControllerShiftRegister2 = ControllerPort2;\n                    }\n                }\n                else\n                {\n                    APU_ControllerPortsStrobed = false;\n                }\n\n                // clock timers\n                APU_ChannelTimer_Pulse1--; // every APU GET cycle.\n                APU_ChannelTimer_Pulse2--;\n                APU_ChannelTimer_Noise--;\n\n\n                //this happens whether a sample is playing or not\n                APU_ChannelTimer_DMC--;\n                APU_ChannelTimer_DMC--; // the table is in CPU cycles, but the count is in APU cycles\n                if (APU_ChannelTimer_DMC == 0)\n                {\n                    APU_ChannelTimer_DMC = APU_DMC_Rate;\n                    DPCM_Up = (APU_DMC_Shifter & 1) == 1;\n                    if (DPCM_Up)\n                    {\n                        if (APU_DMC_Output <= 125) // this is 7 bit, and cannot go above 127\n                        {\n                            APU_DMC_Output += 2;\n                        }\n                    }\n                    else\n                    {\n                        if (APU_DMC_Output >= 2) // this is 7 bit, and cannot go below 0\n                        {\n                            APU_DMC_Output -= 2;\n                        }\n                    }\n                    APU_DMC_Shifter >>= 1; // shift the bits in the shift register\n                    APU_DMC_ShifterBitsRemaining--; // and decrement the \"bits remaining\" counter.\n                    if (APU_DMC_ShifterBitsRemaining == 0) // If there are no bits left,\n                    {\n                        APU_DMC_ShifterBitsRemaining = 8; // it's time for a DMC DMA!\n\n                        if (APU_DMC_BytesRemaining > 0 || APU_SetImplicitAbortDMC4015)\n                        {\n                            if (!DoDMCDMA && CannotRunDMCDMARightNow != 2)\n                            {\n                                // if playing a sample:\n                                DoDMCDMA = true;\n                                DMCDMA_Halt = true;\n                            }\n                            if (APU_SetImplicitAbortDMC4015)\n                            {\n                                APU_ImplicitAbortDMC4015 = true; // check for weird DMA abort behavior\n                                APU_SetImplicitAbortDMC4015 = false;\n                            }\n                            APU_DMC_Shifter = APU_DMC_Buffer; // and set up the shifter with the new values.\n                            APU_Silent = false; // The APU is not silent.\n\n                        }\n                        else\n                        {\n                            APU_Silent = true;\n                        }\n                    }\n                }\n                if (CannotRunDMCDMARightNow > 0)\n                {\n                    CannotRunDMCDMARightNow -= 2;\n                }\n            }\n            else\n            {\n                // If this is a put cycle, transitioning to a get cycle.\n\n                if (Clearing_APU_FrameInterrupt)\n                {\n                    Clearing_APU_FrameInterrupt = false;\n                    APU_Status_FrameInterrupt = false;\n                    IRQ_LevelDetector = false;\n                }\n                // DMC load from 4015\n                if (DMCDMADelay > 0)\n                {\n                    DMCDMADelay--; // there's a small delay beetween the write occurring and the DMA beginning\n                    if (DMCDMADelay == 0 && !DoDMCDMA) // if the DMA is already happening because of the timer\n                    {\n                        DoDMCDMA = true;\n                        DMCDMA_Halt = true;\n                        APU_DMC_Shifter = APU_DMC_Buffer;\n                        APU_Silent = false;\n                    }\n                }\n            }\n            if (APU_DelayedDMC4015 > 0)\n            {\n                APU_DelayedDMC4015--;\n                if (APU_DelayedDMC4015 == 0)\n                {\n                    APU_Status_DMC = APU_Status_DelayedDMC;\n                    if (!APU_Status_DMC)\n                    {\n                        APU_DMC_BytesRemaining = 0;\n                    }\n                }\n            }\n\n            APU_ChannelTimer_Triangle--; // every CPU cycle.\n\n            // clock sequencer\n            if ((APU_FrameCounterReset & 0x80) == 0)\n            {\n                APU_FrameCounterReset--;\n                if ((APU_FrameCounterReset & 0x80) != 0)\n                {\n                    APU_Framecounter = 0;\n                }\n            }\n\n            APU_Framecounter++;\n\n            // We're clocking the APU twice as fast in order to get the frame counter timing to allow the 'half APU cycle' timing.\n            // these numbers are just multiplied by 2.\n\n            if (APU_FrameCounterMode)\n            {\n                // 5 step\n                switch (APU_Framecounter)\n                {\n                    default: break;\n                    case 7457:\n                        APU_QuarterFrameClock = true;\n                        break;\n                    case 14913:\n                        APU_QuarterFrameClock = true;\n                        APU_HalfFrameClock = true;\n                        break;\n                    case 22371:\n                        APU_QuarterFrameClock = true;\n                        break;\n                    case 29829:\n                        break;\n                    case 37281:\n                        APU_QuarterFrameClock = true;\n                        APU_HalfFrameClock = true;\n                        break;\n                    case 37282:\n                        APU_Framecounter = 0;\n                        break;\n                }\n            }\n            else\n            {\n                // 4 step\n                switch (APU_Framecounter)\n                {\n                    default: break;\n                    case 7457:\n                        APU_QuarterFrameClock = true;\n                        break;\n                    case 14913:\n                        APU_QuarterFrameClock = true;\n                        APU_HalfFrameClock = true;\n                        break;\n                    case 22371:\n                        APU_QuarterFrameClock = true;\n                        break;\n                    case 29828:\n                        APU_Status_FrameInterrupt = true;\n                        break;\n                    case 29829:\n                        APU_QuarterFrameClock = true;\n                        APU_Status_FrameInterrupt = true;\n                        IRQ_LevelDetector |= !APU_FrameCounterInhibitIRQ;\n                        APU_HalfFrameClock = true;\n                        break;\n                    case 29830:\n                        APU_Status_FrameInterrupt = !APU_FrameCounterInhibitIRQ;\n                        IRQ_LevelDetector |= !APU_FrameCounterInhibitIRQ;\n\n                        APU_Framecounter = 0;\n\n                        break;\n                }\n\n            }\n\n\n\n\n\n            // perform quarter frame / half frame stuff\n\n            if (APU_QuarterFrameClock)\n            {\n                APU_QuarterFrameClock = false;\n                if (APU_Envelope_StartFlag)\n                {\n                    APU_Envelope_StartFlag = false;\n                    APU_Envelope_DecayLevel = 15;\n\n                }\n                else\n                {\n                    APU_Envelope_DividerClock = true;\n                }\n            }\n\n            if (APU_HalfFrameClock)\n            {\n                if (APU_LengthCounter_ReloadPulse1 && APU_LengthCounter_Pulse1 == 0) { APU_LengthCounter_Pulse1 = APU_LengthCounter_ReloadValuePulse1; } else { APU_LengthCounter_ReloadPulse1 = false; }\n                if (APU_LengthCounter_ReloadPulse2 && APU_LengthCounter_Pulse2 == 0) { APU_LengthCounter_Pulse2 = APU_LengthCounter_ReloadValuePulse2; } else { APU_LengthCounter_ReloadPulse2 = false; }\n                if (APU_LengthCounter_ReloadTriangle && APU_LengthCounter_Triangle == 0) { APU_LengthCounter_Triangle = APU_LengthCounter_ReloadValueTriangle; } else { APU_LengthCounter_ReloadTriangle = false; }\n                if (APU_LengthCounter_ReloadNoise && APU_LengthCounter_Noise == 0) { APU_LengthCounter_Noise = APU_LengthCounter_ReloadValueNoise; } else { APU_LengthCounter_ReloadNoise = false; }\n                APU_HalfFrameClock = false;\n                // length counters and sweep\n                if (!APU_Status_Pulse1) { APU_LengthCounter_Pulse1 = 0; }\n                if (!APU_Status_Pulse2) { APU_LengthCounter_Pulse2 = 0; }\n                if (!APU_Status_Triangle) { APU_LengthCounter_Triangle = 0; }\n                if (!APU_Status_Noise) { APU_LengthCounter_Noise = 0; }\n\n                if (APU_LengthCounter_Pulse1 != 0 && !APU_LengthCounter_HaltPulse1 && !APU_LengthCounter_ReloadPulse1)\n                {\n                    APU_LengthCounter_Pulse1--;\n                }\n                if (APU_LengthCounter_Pulse2 != 0 && !APU_LengthCounter_HaltPulse2 && !APU_LengthCounter_ReloadPulse2)\n                {\n                    APU_LengthCounter_Pulse2--;\n                }\n                if (APU_LengthCounter_Triangle != 0 && !APU_LengthCounter_HaltTriangle && !APU_LengthCounter_ReloadTriangle)\n                {\n                    APU_LengthCounter_Triangle--;\n                }\n                if (APU_LengthCounter_Noise != 0 && !APU_LengthCounter_HaltNoise && !APU_LengthCounter_ReloadNoise)\n                {\n                    APU_LengthCounter_Noise--;\n                }\n            }\n            else\n            {\n                if (APU_LengthCounter_ReloadPulse1) { APU_LengthCounter_Pulse1 = APU_LengthCounter_ReloadValuePulse1; }\n                if (APU_LengthCounter_ReloadPulse2) { APU_LengthCounter_Pulse2 = APU_LengthCounter_ReloadValuePulse2; }\n                if (APU_LengthCounter_ReloadTriangle) { APU_LengthCounter_Triangle = APU_LengthCounter_ReloadValueTriangle; }\n                if (APU_LengthCounter_ReloadNoise) { APU_LengthCounter_Noise = APU_LengthCounter_ReloadValueNoise; }\n                APU_LengthCounter_ReloadPulse1 = false;\n                APU_LengthCounter_ReloadPulse2 = false;\n                APU_LengthCounter_ReloadTriangle = false;\n                APU_LengthCounter_ReloadNoise = false;\n            }\n\n            APU_LengthCounter_HaltPulse1 = ((APU_Register[0] & 0x20) != 0);\n            APU_LengthCounter_HaltPulse2 = ((APU_Register[4] & 0x20) != 0);\n            APU_LengthCounter_HaltTriangle = ((APU_Register[8] & 0x80) != 0);\n            APU_LengthCounter_HaltNoise = ((APU_Register[0xC] & 0x20) != 0);\n\n\n\n        } // and that's it for the APU cycle\n\n        // PPU variables\n\n        public byte PPUBus; // The databus of the Picture Processing Unit\n        public int[] PPUBusDecay = new int[8];\n        const int PPUBusDecayConstant = 1786830; // 20 frames. Approximately how long it takes for the PPU bus to decay on my console.\n        public byte PPUOAMAddress; // The address used to index into Object Attribute Memory\n        public bool PPUStatus_VBlank; // This is set during Vblank, and cleared at the end, or if $2002 is read. This value can be read in address $2002\n        public bool PPUStatus_PendingSpriteZeroHit; // If a sprite zero hit occurs, this is set. This toggles PPUStatus_SpriteZeroHit on the next half-ppu-cycle.\n        public bool PPUStatus_PendingSpriteZeroHit2; // Actually theres a 1.5 dot delay on this one.\n        public bool PPUStatus_SpriteZeroHit; // If a sprite zero hit occurs, this is set. This value can be read in address $2002\n        public bool PPUStatus_SpriteZeroHit_Delayed;\n        public bool PPUStatus_SpriteOverflow; // If a scanline had more than 8 objects in range, this is set. This value can be read in address $2002\n        public bool PPUStatus_SpriteOverflow_Delayed;\n\n        public bool PPU_VSET; // This line is high for half a ppu cycle at the start of scanline 241.\n        public bool PPU_VSET_Latch1; // A latch used in the timing for the VBlank flag.\n        public bool PPU_VSET_Latch2; // A latch used in the timing for the VBlank flag.\n        public bool PPU_Read2002; // This clears the VBlank flag.\n\n        bool PPU_Spritex16; // Are sprites using 8x8 mode, or 8x16 mode? Set by writing to $2000\n\n        public ushort PPU_Scanline; // Which scanline is the PPU currently on\n        public ushort PPU_Dot; // Which dot of the scanline is the PPU currently on\n\n        public bool PPU_VRegisterChangedOutOfVBlank;    // when changing the v register (Read write address) out of vblank, palettes can become corrupted\n        public bool PPU_OAMCorruptionRenderingDisabledOutOfVBlank;  // When rendering is disabled on specific dots of visible scanlines, OAM data can become corrupted\n        public bool PPU_PendingOAMCorruption;// The corruption doesn't take place until rendering is re-enabled.\n        public byte PPU_OAMCorruptionIndex;  // The object that gets corrupted depends on when the data was corrupted\n        // OAM corruption during OAM evaluation happens with the instant write to $2001 using the databus value. Other parts of sprite evaluation apparently do not.\n        public bool PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant;  // When rendering is disabled on specific dots of visible scanlines, OAM data can become corrupted\n        public bool PPU_OAMCorruptionRenderingEnabledOutOfVBlank; // If enabling rendering outside vblank, there are alignment specific effects.\n        public bool PPU_OAMEvaluationCorruptionOddCycle; // If rendering is disabled during OAM evaluation, it matters if it was on an odd or even cycle.\n        public bool PPU_OAMEvaluationObjectInRange; // If rendering is disabled during OAM evaluation, it matters if the most recent object evaluated was in vertical range of this scanline.\n        public bool PPU_OAMEvaluationObjectInXRange; // If rendering is disabled during OAM evaluation, it matters if the most recent object evaluated was in vertical range of this scanline.\n\n        public bool PPU_PaletteCorruptionRenderingDisabledOutOfVBlank;  // When rendering is disabled on specific dots of visible scanlines, OAM data can become corrupted\n\n\n        byte PPU_AttributeLatchRegister;\n        ushort PPU_BackgroundAttributeShiftRegisterL; // 8 bit latch for the background tile attributes low bit plane.\n        ushort PPU_BackgroundAttributeShiftRegisterH; // 8 bit latch register for the background tile attributes high bit plane.\n        ushort PPU_BackgroundPatternShiftRegisterL; // 16 bit shift register for the background tile pattern low bit plane.\n        ushort PPU_BackgroundPatternShiftRegisterH; // 16 bit shift register for the background tile pattern high bit plane.\n\n        //TempPPUAddr\n        public byte PPU_FineXScroll; // Set when writing to address $2005. 3 bits. This is up to a 7 pixel offset when rendering the screen.\n\n        byte[] PPU_SpriteShiftRegisterL = new byte[8]; // 8 bit shift register for a sprite's low bit plane. Secondary OAM can have up to 8 object in it.\n        byte[] PPU_SpriteShiftRegisterH = new byte[8]; // 8 bit shift register for a sprite's high bit plane. Secondary OAM can have up to 8 object in it.\n\n        byte[] PPU_SpriteAttribute = new byte[8]; // Secondary OAM attribute values. Secondary OAM can have up to 8 objects in it.\n        byte[] PPU_SpritePattern = new byte[8]; // Secondary OAM pattern values. Secondary OAM can have up to 8 objects in it.\n        byte[] PPU_SpriteXposition = new byte[8]; // Secondary OAM x positions. Secondary OAM can have up to 8 objects in it.\n        byte[] PPU_SpriteYposition = new byte[8]; // Secondary OAM y positions. Secondary OAM can have up to 8 objects in it.\n\n        byte[] PPU_SpriteShifterCounter = new byte[8]; // This counter tracks how long until the objects are drawn.\n\n\n        bool PPU_NextScanlineContainsSpriteZero;    // If this upcoming scanline contains sprite zero\n        bool PPU_CurrentScanlineContainsSpriteZero; // if the sprite evaluation for this current scanline contained sprite zero. Used for Sprite Zero Hit detection.\n\n        public byte PPU_SpritePatternL; // Temporary value used in sprite evaluation.\n        public byte PPU_SpritePatternH; // Temporary value used in sprite evaluation.\n\n\n        bool PPU_Mask_Greyscale;         // Set by writing to $2001. If set, only use color 00, 10, 20, or 30 when drawing a pixel.\n        bool PPU_Mask_8PxShowBackground; // Set by writing to $2001. If set, the background will be visible in the 8 left-most pixels of the screen.\n        bool PPU_Mask_8PxShowSprites;    // Set by writing to $2001. If set, the sprites will be visible in the 8 left-most pixels of the screen.\n        bool PPU_Mask_ShowBackground;    // Set by writing to $2001. If set, the background will be visible. Anything that requires rendering to be enabled will run, even if it doesn't involve the background.\n        bool PPU_Mask_ShowSprites;       // Set by writing to $2001. If set, the sprites will be visible.  Anything that requires rendering to be enabled will run, even if it doesn't involve sprites.\n        bool PPU_Mask_EmphasizeRed;      // Set by writing to $2001. Adjusts the colors on screen to be a bit more red.\n        bool PPU_Mask_EmphasizeGreen;    // Set by writing to $2001. Adjusts the colors on screen to be a bit more green.\n        bool PPU_Mask_EmphasizeBlue;     // Set by writing to $2001. Adjusts the colors on screen to be a bit more blue.\n\n        bool PPU_Mask_ShowBackground_Delayed; // Sprite evaluation has a 1 ppu cycle delay on checking if rendering is enabled.\n        bool PPU_Mask_ShowSprites_Delayed; // Sprite evaluation has a 1 ppu cycle delay on checking if rendering is enabled.\n        bool PPU_Mask_ShowBackground_Instant; // OAM evaluation will stop immediately if writing to $2001\n        bool PPU_Mask_ShowSprites_Instant; // OAM evaluation will stop immediately if writing to $2001\n\n        byte PPU_LowBitPlane; // Temporary value used in background shift register preparation.\n        byte PPU_HighBitPlane;// Temporary value used in background shift register preparation.\n        byte PPU_Attribute; // Temporary value used in background shift register preparation.\n\n        public ushort PPU_PatternAddressRegister_CHR; // PAR\n        public ushort PPU_PatternAddressRegister_NT;  // PAR\n        public ushort PPU_PatternAddressRegister_AT;  // PAR\n        public ushort PPU_PAR_MUX;                    // PAR\n\n        bool PPU_CanDetectSpriteZeroHit; // Only 1 sprite zero hit is allowed per frame. This gets set if a sprite zero hit occurs, and cleared at the end of vblank.\n\n        public bool PPU_A12_Prev; // The MMC3 chip's IRQ counter is changed whenever bit 12 of the PPU Address is changing from a 0 to a 1. This is recorded at the start of a PPU cycle, and checked at the end.\n\n        public bool PPU_OddFrame; // Every other frame is 1 ppu cycle shorter.\n\n        public byte DotColor; // The pixel output is delayed by 2 dots.\n        public byte PrevDotColor; // This is the value from last cycle.\n        public byte PrevPrevDotColor; // And this is from 2 cycles ago.\n        public byte PrevPrevPrevDotColor; // And this is from 2 cycles ago.\n        public int PrevPrevPrevPrevDotColor; // This is used with NTSC signal decoding.\n        public byte PaletteRAMAddress;\n        public bool ThisDotReadFromPaletteRAM;\n\n\n        public bool NMI_PinsSignal; // I'm using this to detect the rising edge of $2000.7 and $2002.7\n        public bool NMI_PreviousPinsSignal; // I'm using this to detect the rising edge of $2000.7 and $2002.7\n        public bool IRQ_LevelDetector; // If set, it's time to run an IRQ whenever this is detected\n        public bool NMILine; // Set to true if $2000.7 and $2002.7 are both set. This is checked during the second half od a CPU cycle.\n        public bool IRQLine; // Set during phi2 to true if the IRQ level detector is low.\n\n        bool CopyV = false; // set by writes to $2006. If it occurs on the same dot the scroll values are naturally incremented, some bugs occur.\n        bool SkippedPreRenderDot341 = false;\n\n        void _EmulatePPU()\n        {\n\n            // When writing to ppu registers, there's a slight delay before resulting action is taken.\n            // This delay can vary depending on the CPU/PPU alignment.\n\n            // For instance, after writing to $2006, this delay value will either be 4 or 5.\n            CopyV = false;\n            if (PPU_Update2006Delay > 0)\n            {\n                PPU_Update2006Delay--; // this counts down,\n                if (PPU_Update2006Delay == 0) // and when it reaches zero\n                {\n                    ushort temp_Prev_V = PPU_v;\n                    CopyV = true;\n                    PPU_v = PPU_t; // the PPU_ReadWriteAddress is updated!\n                    PPU_AddressBus = PPU_v; // This value is the same thing.\n                    if ((temp_Prev_V & 0x3FFF) >= 0x3F00 && (PPU_AddressBus & 0x3FFF) < 0x3F00) // Palette corruption check. Are we leaving Palette ram?\n                    {\n                        if ((PPU_Scanline < 240) && PPU_Dot <= 256) // if this dot is visible\n                        {\n                            if ((temp_Prev_V & 0xF) != 0)  // also, Palette corruption only happens if the previous address did not end in a 0\n                            {\n                                PPU_VRegisterChangedOutOfVBlank = true;\n                            }\n                        }\n                    }\n                }\n            }\n            // after writing to $2005, there is either a 1 or 2 cycle delay.\n            if (PPU_Update2005Delay > 0)\n            {\n                PPU_Update2005Delay--;\n                if (PPU_Update2005Delay == 0)\n                {\n                    if (!PPUAddrLatch)\n                    {\n                        // if this is the first write to $2005\n                        PPU_FineXScroll = (byte)(PPU_Update2005Value & 7); // This updates the fine X scroll\n                        PPU_t = (ushort)((PPU_t & 0b0111111111100000) | (PPU_Update2005Value >> 3)); // as well as changing the 't' register.\n                    }\n                    else\n                    {\n                        // if this is the second write to $2005\n                        PPU_t = (ushort)((PPU_t & 0b0000110000011111) | (((PPU_Update2005Value & 0xF8) << 2) | ((PPU_Update2005Value & 7) << 12))); // this also writes to 't'\n                    }\n                    PPUAddrLatch = !PPUAddrLatch; // flip the latch\n                }\n            }\n\n            // Updating the scroll registers during screen rendering\n            if (PPU_Scanline < 240 || PPU_Scanline == 261)// if this is the pre-render line, or any line before vblank\n            {\n                if ((PPU_Mask_ShowBackground || PPU_Mask_ShowSprites))\n                {\n                    if (PPU_Dot == 256) //The Y scroll is incremented on dot 256.\n                    {\n                        PPU_IncrementScrollY();\n                    }\n                    else if (PPU_Dot == 257) //The X scroll is reset on dot 257.\n                    {\n                        PPU_ResetXScroll();\n                    }\n                    if (PPU_Dot >= 280 && PPU_Dot <= 304 && PPU_Scanline == 261) //numbers from the nesdev wiki\n                    {\n                        PPU_ResetYScroll(); //The Y scroll is reset on every dot from 280 through 304 on the pre-render scanline.\n                    }\n                }\n            }\n\n            // Increment the PPU dot\n            PPU_Dot++;\n            if (PPU_Dot > 340) // There are only 341 dots per scanline\n            {\n                PPU_Dot = 0;  // reset the dot back to 0\n                PPU_Scanline++;     // and increment the scanline\n                // Sprite zero hits rely on the previous scanline's sprite evaluation.\n\n                if (PPU_Scanline > 261) // There are 262 scanlines in a frame.\n                {\n                    PPU_Scanline = 0;   // reset to scanline 0.\n                }\n            }\n\n            if (PPU_Scanline == 241) // If this is the first scanline of VBLank\n            {\n                if (PPU_Dot == 0)\n                {\n                    // If Address $2002 is read during the next ppu cycle, the PPU Status flags aren't set.\n                    // These variables are used to check if Address $2002 is read during the next ppu cycle.\n                    // I usually refer to this as the $2002 race condition.\n                    // The more proper term would be \"Vblank/NMI flag suppression\".\n\n                    // oh- and also if we're running a fm2 TAS file, due to FCEUX's incorrect timing of the first frame, I need to prevent this from being set just a few cycles after power on.\n                    if (!SyncFM2)\n                    {\n                        PPU_PendingVBlank = true;\n                    }\n                    else\n                    {\n                        SyncFM2 = false;\n                    }\n                }\n                if (PPU_Dot == 1)\n                {\n                    PPU_RESET = false;\n\n                    // else, address $2002 was read on this ppu cycle. no VBlank flag.\n                    if (!PPU_ShowScreenBorders)\n                    {\n                        FrameAdvance_ReachedVBlank = true; // Emulator specific stuff. Used for frame advancing to detect the frame has ended, and nothing else.\n                    }\n                    if (!ClockFiltering) // specifically for TASing stuff. Increment the index for the input log.\n                    {\n                        if (TAS_ReadingTAS && TAS_InputSequenceIndex > 0 && TAS_InputSequenceIndex < TAS_ResetLog.Length && TAS_ResetLog[TAS_InputSequenceIndex])\n                        {\n                            Reset();\n                        }\n                        // If this was using \"SubFrame\", TAS_InputSequenceIndex is incremented whenever the controller is strobed.\n                        // Instead, I increment the index here at the start of vblank.\n                        TAS_InputSequenceIndex++;\n                    }\n\n\n                }\n\n            }\n            else if (PPU_Scanline == 242 && PPU_Dot == 1)\n            {\n                if (PPU_ShowScreenBorders && !PPU_DecodeSignal) // if we're showing the boarders, we need to wait for 2 more scanlines to render.\n                {\n                    FrameAdvance_ReachedVBlank = true; // Emulator specific stuff. Used for frame advancing to detect the frame has ended, and nothing else.\n                }\n            }\n            else if (PPU_Scanline == 260 && PPU_Dot == 340)\n            {\n                PPU_OddFrame = !PPU_OddFrame; // I guess this could happen on pretty much any cycle?\n\n            }\n            else if (PPU_Scanline == 261 && PPU_Dot == 1)\n            {\n                // On dot 1 of the pre-render scanline, all of these flags are cleared.\n                // You might be looking at the results of my \"$2002 Flag Clear Timing\" test from the AccuracyCoin test ROM and thinking, \"Hold on. That can't be right!\"\n                // Well, it is. You see, PPUStatus_VBlank is read at the beginning of the read, while PPUStatus_SpriteZeroHit and PPUStatus_SpriteOverflow are read at the end of the read.\n                // This means about 1 and 7/8 ppu cycles pass between the start of the read and the end, so thes values are seemingly cleared on different cycles, but they are in-fact cleared at the same time.\n                PPUStatus_VBlank = false;\n                PPU_CanDetectSpriteZeroHit = true;\n                PPUStatus_SpriteZeroHit = false;\n                PPUStatus_SpriteOverflow = false;\n                PPUStatus_SpriteZeroHit_Delayed = false;\n            }\n\n            else if (PPU_Scanline == 0 && PPU_Dot == 1)\n            {\n                if (PPU_ShowScreenBorders && PPU_DecodeSignal) // if we're showing the boarders, we need to wait for scanline 0.\n                {\n                    FrameAdvance_ReachedVBlank = true; // Emulator specific stuff. Used for frame advancing to detect the frame has ended, and nothing else.\n                }\n            }\n\n            PPU_VSET_Latch1 = !PPU_VSET; //  VSET_Latch1 is latched with /VSET on the first half of a PPU cycle.\n            if (PPU_VSET && !PPU_VSET_Latch2)\n            {\n                PPUStatus_VBlank = true;\n            }\n            if (PPU_Read2002)\n            {\n                PPU_Read2002 = false;\n                PPUStatus_VBlank = false;\n            }\n\n            PPUStatus_SpriteOverflow_Delayed = PPUStatus_SpriteOverflow;\n\n\n            \n            // Right now, I'm only emulating MMC3's IRQ counter in this function.\n            PPU_MapperSpecificFunctions();\n            PPU_A12_Prev = (PPU_AddressBus & 0b0001000000000000) != 0; // Record the value of the A12. This is used in the PPU_MapperSpecificFunctions(), so if this changes between here and next ppu cycle, we'll know.\n            if (PPU_OddFrame && (PPU_Mask_ShowBackground || PPU_Mask_ShowSprites))\n            {\n                if (PPU_Scanline == 261 && PPU_Dot == 340)\n                {\n                    // On every other frame, dot 0 of scanline 0 is skipped.\n                    // this cycle is technically (0,0), but this still makes the Nametable fetch during the last cycle of the pre-render line\n                    PPU_Scanline = 0;\n                    PPU_Dot = 0;\n                    SkippedPreRenderDot341 = true;\n                }\n            }\n            if (PPU_OddFrame && (PPU_Mask_ShowBackground || PPU_Mask_ShowSprites) && PPU_Scanline == 0 && PPU_Dot == 2)\n            {\n                SkippedPreRenderDot341 = false; // This variable is used for some esoteric business on dot 1 of scanline 0.\n            }\n            // Okay, now that we're updated all those flags, let's render stuff to the screen!\n\n            // let's establish the order of operations.\n            // Sprite evaluation\n            // then calculate the color for the next dot.\n\n            //but to complicate things, the delay after writing to $2001 happens between those 2 steps, and also on a specific alignment, this delay is 1 cycle longer for sprite evaluation.\n\n            // If this is NOT phase 1\n            if ((CPUClock & 3) != 3)\n            {\n                // sprite evaluation has a 1 ppu cycle delay before recognizing these flags were set or cleared.\n                PPU_Mask_ShowBackground_Delayed = PPU_Mask_ShowBackground;\n                PPU_Mask_ShowSprites_Delayed = PPU_Mask_ShowSprites;\n            }\n\n            PPU_DATA_StateMachine();\n\n            if ((PPU_Scanline < 240 || PPU_Scanline == 261))// if this is the pre-render line, or any line before vblank\n            {\n                // Sprite evaluation\n                if (PPU_Scanline < 241 || PPU_Scanline == 261)\n                {\n                    PPU_Render_SpriteEvaluation(); // fill in secondary OAM, and set up various arrays of sprite properties.\n                }\n            }\n\n            if ((CPUClock & 3) == 3)\n            {\n                // on phase 1,\n                // sprite evaluation has a 2 ppu cycle delay before recognizing these flags were set or cleared.\n                PPU_Mask_ShowBackground_Delayed = PPU_Mask_ShowBackground;\n                PPU_Mask_ShowSprites_Delayed = PPU_Mask_ShowSprites;\n            }\n\n            if (!PPU_Mask_ShowBackground && !PPU_Mask_ShowSprites)\n            {\n                PPU_AddressBus = PPU_v; // the address bus is always v when rendering is disabled.\n                // TODO: Is this occuring one ppu cycle too late???\n                // I specifically moved this here (outside of the following if statements) because it broke nes_reset_state_detect-letters.nes on alignment 1.\n            }\n            // after sprite evaluation, but before screen rendering...\n            if (PPU_Update2001Delay > 0) // if we wrote to 2001 recently\n            {\n                PPU_Update2001Delay--;\n                if (PPU_Update2001Delay == 0) // if we've waited enough cycles, apply the changes\n                {\n                    PPU_Mask_8PxShowBackground = (PPU_Update2001Value & 0x02) != 0;\n                    PPU_Mask_8PxShowSprites = (PPU_Update2001Value & 0x04) != 0;\n                    PPU_Mask_ShowBackground = (PPU_Update2001Value & 0x08) != 0;\n                    PPU_Mask_ShowSprites = (PPU_Update2001Value & 0x10) != 0;\n\n                    PPU_Mask_ShowBackground_Instant = PPU_Mask_ShowBackground; // now that the PPU has updated, OAM evaluation will also recognize the change\n                    PPU_Mask_ShowSprites_Instant = PPU_Mask_ShowSprites;\n                }\n            }\n            if (PPU_Update2001OAMCorruptionDelay > 0) // if we wrote to 2001 recently\n            {\n                PPU_Update2001OAMCorruptionDelay--;\n                if (PPU_Update2001OAMCorruptionDelay == 0) // if we've waited enough cycles, apply the changes\n                {\n                    if (PPU_WasRenderingBefore2001Write && (PPU_Update2001Value & 0x08) == 0 && (PPU_Update2001Value & 0x10) == 0)\n                    {\n                        if ((PPU_Scanline < 240 || PPU_Scanline == 261)) // if this is the pre-render line, or any line before vblank\n                        {\n                            if (!PPU_PendingOAMCorruption) // due to OAM corruption occurring inside OAM evaluation before this even occurs, make sure OAM isn't already corrupt\n                            {\n                                PPU_OAMCorruptionRenderingDisabledOutOfVBlank = true;\n                            }\n                        }\n                    }\n                }\n            }\n            if (PPU_Update2001EmphasisBitsDelay > 0)\n            {\n                PPU_Update2001EmphasisBitsDelay--;\n                if (PPU_Update2001EmphasisBitsDelay == 0)\n                {\n                    PPU_Mask_Greyscale = (PPU_Update2001Value & 0x01) != 0;\n                    PPU_Mask_EmphasizeRed = (PPU_Update2001Value & 0x20) != 0;\n                    PPU_Mask_EmphasizeGreen = (PPU_Update2001Value & 0x40) != 0;\n                    PPU_Mask_EmphasizeBlue = (PPU_Update2001Value & 0x80) != 0;\n                }\n            }\n\n            PrevPrevPrevDotColor = PrevPrevDotColor; // Drawing a color to the screen has a 3(?) ppu cycle delay between deciding the color, and drawing it.\n            PrevPrevDotColor = PrevDotColor;\n            PrevDotColor = DotColor; // These variables here just record the color, and swap them through these variables so it can be used 3 cycles after it was chosen.\n            if ((PPU_Scanline < 240 || PPU_Scanline == 261))// if this is the pre-render line, or any line before vblank\n            {\n                if ((PPU_Dot >= 1 && PPU_Dot <= 256) || (PPU_Dot >= 321 && PPU_Dot <= 336)) // if this is a visible pixel, or preparing the start of next scanline\n                {\n                    if ((PPU_Mask_ShowBackground_Delayed || PPU_Mask_ShowSprites_Delayed)) // if rendering background or sprites\n                    {\n                        PPU_Render_ShiftRegistersAndBitPlanes(); // update shift registers for the background.\n                    }\n                }\n                else if (PPU_Dot >= 337 || PPU_Dot == 0)\n                {\n                    if ((PPU_Mask_ShowBackground_Delayed || PPU_Mask_ShowSprites_Delayed)) // if rendering background or sprites\n                    {\n                        PPU_Render_ShiftRegistersAndBitPlanes_DummyNT();\n                    }\n                }\n\n                if ((PPU_Dot > 0 && PPU_Dot <= 256)) // if this is a visible pixel, or preparing the start of next scanline\n                {\n                    if (PPU_Scanline < 241)\n                    {\n                        PPU_Render_CalculatePixel(false); // this determines the color of the pixel being drawn.\n                    }\n                    UpdateSpriteShiftRegisters(); // update shift registers for the sprites.\n                }\n                else\n                {\n                    if (PPU_ShowScreenBorders) // Draw the pixels in the boarder too.\n                    {\n                        PPU_Render_CalculatePixel(true); // this determines the color of the pixel being drawn.\n                    }\n                }\n\n\n                if (!PPU_ShowScreenBorders)\n                {\n                    DrawToScreen();\n\n                    if (PPU_DecodeSignal && (PPU_Dot == 0) && PPU_Scanline < 241)\n                    {\n                        ntsc_signal_of_dot_0 = ntsc_signal;\n                        chosenColor = PaletteRAM[0x00] & 0x3F;\n                        if (PPU_Mask_Greyscale) // if the ppu greyscale mode is active,\n                        {\n                            chosenColor &= 0x30; //To force greyscale, bitwise AND this color with 0x30\n                        }\n                        // emphasis bits\n                        int emphasis = 0;\n                        if (PPU_Mask_EmphasizeRed) { emphasis |= 0x40; } // if emhpasizing r, add 0x40 to the index into the palette LUT.\n                        if (PPU_Mask_EmphasizeGreen) { emphasis |= 0x80; } // if emhpasizing g, add 0x80 to the index into the palette LUT.\n                        if (PPU_Mask_EmphasizeBlue) { emphasis |= 0x100; } // if emhpasizing b, add 0x100 to the index into the palette LUT.\n                        PrevPrevPrevPrevDotColor = chosenColor | emphasis; // set up samples for dot 1\n                        PPU_SignalDecode(chosenColor | emphasis);\n                    }\n                    if (PPU_DecodeSignal && (PPU_Dot == 260) && PPU_Scanline < 241)\n                    {\n                        PPU_SignalDecode(PrevPrevPrevPrevDotColor);\n                    }\n                    else if (PPU_DecodeSignal && (PPU_Dot == 261) && PPU_Scanline < 241)\n                    {\n                        RenderNTSCScanline();\n                    }\n                }\n            }\n            else if (PPU_ShowScreenBorders)\n            {\n                PPU_Render_CalculatePixel(true); // this determines the color of the pixel being drawn.\n            }\n            if (PPU_ShowScreenBorders)\n            {\n                DrawToBorderedScreen();\n            }\n            ThisDotReadFromPaletteRAM = false;\n\n            PPU_DATA_StateMachine2();\n\n            if (PPU_DecodeSignal)\n            {\n                ntsc_signal += 8;\n                ntsc_signal %= 12;\n            }\n\n            if (Logging && LoggingPPU)\n            {\n                Debug_PPU();\n            }\n\n        } // and that's all for the PPU cycle!\n\n        bool PPUActiveForShiftRegisterUpdate;\n        void _EmulateHalfPPU()\n        {\n            // Oh boy, it's time for half PPU cycles.            \n            if ((PPU_Scanline < 240 || PPU_Scanline == 261))// if this is the pre-render line, or any line before vblank\n            {\n                if(PPU_Dot == 320)\n                {\n\n                }\n                if ((PPU_Dot > 0 && PPU_Dot <= 257) || (PPU_Dot > 320 && PPU_Dot <= 336)) // if this is a visible pixel, or preparing the start of next scanline\n                {\n                    if ((PPU_Mask_ShowBackground || PPU_Mask_ShowSprites)) // if rendering background or sprites\n                    {\n                        PPU_UpdateBackgroundShiftRegisters(); // shift all the shift registers 1 bit\n                    }\n                }\n            }\n\n            PPU_Render_CommitShiftRegistersAndBitPlanes();\n            \n            PPU_VSET = false;\n            if (PPU_PendingVBlank)\n            {\n                PPU_PendingVBlank = false;\n                PPU_VSET = true;\n            }\n            // PPU_VSET_Latch1 gets inverted, and that becomes the state of PPU_VSET_Latch2\n            PPU_VSET_Latch2 = !PPU_VSET_Latch1;\n\n            if ((PPU_Mask_ShowBackground || PPU_Mask_ShowSprites) && PPU_Scanline < 240)\n            {\n                if (PPU_Dot == 0 || PPU_Dot > 320)\n                {\n                    PPU_OAMBuffer = OAM2[0];\n                }\n                else if (PPU_Dot > 0 && PPU_Dot <= 64)\n                {\n                    PPU_OAMBuffer = 0xFF;\n                }\n                else if (PPU_Dot <= 256)\n                {\n                    PPU_OAMBuffer = PPU_OAMLatch;\n                }\n                else\n                {\n                    PPU_OAMBuffer = PPU_OAMLatch;\n                }\n            }\n\n            PPUStatus_SpriteZeroHit_Delayed = PPUStatus_SpriteZeroHit;\n            if (PPUStatus_PendingSpriteZeroHit2)\n            {\n                PPUStatus_PendingSpriteZeroHit2 = false;\n                PPUStatus_SpriteZeroHit = true;\n            }\n            if (PPUStatus_PendingSpriteZeroHit)\n            {\n                PPUStatus_PendingSpriteZeroHit = false;\n                PPUStatus_PendingSpriteZeroHit2 = true;\n            }\n\n            PPU_DATA_StateMachine_Half();\n\n        }\n\n        public bool PPU_2007_Read;\n        public bool PPU_2007_Read_SR;\n        public bool[] PPU_2007_Read_Latches = new bool[5];\n        public bool PPU_2007_PD_RB;\n        public bool PPU_2007_ReadALE;\n        public bool PPU_2007_Read_H0_Latch;\n        public bool PPU_2007_Read_XRB;\n\n        public bool PPU_READ; // The lower 8 bits of the address bus are being used as data pins for a read.\n\n        public bool PPU_2007_Write;\n        public bool PPU_2007_Write_SR;\n        public bool[] PPU_2007_Write_Latches = new bool[5];\n        public bool PPU_2007_DB_PAR;\n        public bool PPU_2007_WriteALE;\n        public bool PPU_2007_TStep_Latch;\n        public bool PPU_2007_TStep;\n\n        public bool PPU_2007_BLNK_Latch;\n        public bool PPU_2007_PaletteRAMEnable;\n        public byte PPU_2007_WriteData;\n\n        public bool PPU_WRITE; // The lower 8 bits of the address bus are being used as data pins for a write.\n        void PPU_DATA_StateMachine()\n        {\n            bool BLNK = (!PPU_Mask_ShowBackground && !PPU_Mask_ShowSprites) || (PPU_Scanline >= 240 && PPU_Scanline < 261);\n            PPU_2007_BLNK_Latch = BLNK;\n            bool H0_DASH = (PPU_Dot - 1 & 1) != 0;\n\n            PPU_2007_PaletteRAMEnable = ((PPU_AddressBus & 0x3F00) == 0x3F00) && PPU_2007_BLNK_Latch;\n            PPU_2007_Read_XRB = PPU_2007_Read && PPU_2007_PaletteRAMEnable;\n                     \n            PPU_2007_Read_Latches[0] = PPU_2007_Read_SR;\n            if(PPU_2007_Read)\n            {\n                PPU_2007_Read = false; // I put this in an if statement for easier debugging / breakpoint placement.\n            }\n            PPU_2007_Read_Latches[2] = !PPU_2007_Read_Latches[1];\n            PPU_2007_Read_Latches[4] = !PPU_2007_Read_Latches[3];\n            PPU_2007_PD_RB = PPU_2007_Read_Latches[4] && !PPU_2007_Read_Latches[2];\n            PPU_2007_ReadALE = !PPU_2007_Read_Latches[4] && PPU_2007_Read_Latches[2];\n            PPU_2007_Read_H0_Latch = (PPU_Dot - 1 & 1) != 0;\n\n\n            PPU_READ = (PPU_2007_PD_RB || (!BLNK && PPU_2007_Read_H0_Latch)); // even ppu cycles outside of blanking always read. Also read if we are reading $2007.\n\n            PPU_2007_Write_Latches[0] = PPU_2007_Write_SR;\n            if (PPU_2007_Write)\n            {\n                PPU_2007_Write = false; // I put this in an if statement for easier debugging / breakpoint placement.\n            }\n            PPU_2007_Write_Latches[2] = !PPU_2007_Write_Latches[1];\n            PPU_2007_Write_Latches[4] = !PPU_2007_Write_Latches[3];\n            PPU_2007_WriteALE = !PPU_2007_Write_Latches[4] && PPU_2007_Write_Latches[2];\n\n            PPU_2007_TStep_Latch = PPU_2007_DB_PAR;\n           \n            bool b = (!BLNK && !H0_DASH); // If you are on an even dot out of a blanking period\n            PPU_ALE = (PPU_2007_ReadALE || PPU_2007_WriteALE || b);\n\n            if ((PPU_2007_ReadALE || PPU_2007_WriteALE))\n            {\n                if (!PPU_READ)\n                {\n                    PPU_AddressBus = PPU_v;\n                    PPU_OctalLatch = (byte)PPU_AddressBus;\n                }\n            }\n        }\n        void PPU_DATA_StateMachine2()\n        {\n            \n            if (PPU_2007_PD_RB)\n            {\n                PPU_ReadBuffer = Cart.MapperChip.FetchPPU();\n                if (PPU_ALE)\n                {\n                    PPU_OctalLatch = (byte)PPU_AddressBus;\n                }\n            }           \n        }\n        void PPU_DATA_StateMachine_Half()\n        {\n            PPU_2007_TStep = (PPU_2007_TStep_Latch || PPU_2007_PD_RB);\n            if (PPU_2007_TStep) // If this occurs inside PPU_DATA_StateMachine() instead, the timing is wrong, and this breaks SMB1's title screen.\n            {\n                if (!PPU_2007_BLNK_Latch)\n                {\n                    PPU_IncrementScrollY();\n                }\n                else\n                {\n                    PPU_v += (ushort)(PPUControlIncrementMode32 ? 32 : 1);\n                }\n            }\n\n            PPU_ALE = (PPU_2007_ReadALE || PPU_2007_WriteALE);\n            if (PPU_2007_PD_RB)\n            {\n                PPU_ReadBuffer = Cart.MapperChip.FetchPPU();\n                if (PPU_ALE)\n                {\n                    // pretty sure this can never happen, but keep it just in case.\n                    PPU_OctalLatch = (byte)PPU_AddressBus;\n                }\n            }\n            PPU_2007_Read_Latches[1] = !PPU_2007_Read_Latches[0];\n            PPU_2007_Read_Latches[3] = !PPU_2007_Read_Latches[2];\n            if (!PPU_2007_Read_Latches[3])\n            {\n                PPU_2007_Read_SR = false;\n            }\n\n            PPU_2007_Write_Latches[1] = !PPU_2007_Write_Latches[0];\n            PPU_2007_Write_Latches[3] = !PPU_2007_Write_Latches[2];\n            if (!PPU_2007_Write_Latches[3])\n            {\n                PPU_2007_Write_SR = false;\n            }\n            PPU_2007_DB_PAR = PPU_2007_Write_Latches[1] && !PPU_2007_Write_Latches[3];\n            PPU_WRITE = !PPU_2007_PaletteRAMEnable && PPU_2007_DB_PAR;\n            if (PPU_2007_DB_PAR) // Using PAR instead of PPU_WRITE, since I re-use StorePPUData() for writes to palette RAM.\n            {\n                StorePPUData(PPU_AddressBus, PPU_2007_WriteData);\n            }\n        }\n\n\n\n        void DrawToScreen()\n        {\n            if (PPU_Dot > 3 && PPU_Dot <= 259 && PPU_Scanline < 241) // the process of drawing a dot to the screen actually has a 2 ppu cycle delay, which the emphasis bits happen after\n            {\n                // in other words, the geryscale/emphasis bits can affect the color that was decided 2 ppu cycles ago.\n                chosenColor = PrevPrevPrevDotColor;\n                if (PPU_Mask_Greyscale) // if the ppu greyscale mode is active,\n                {\n                    chosenColor &= 0x30; //To force greyscale, bitwise AND this color with 0x30\n                }\n                // emphasis bits\n                int emphasis = 0;\n                if (PPU_Mask_EmphasizeRed) { emphasis |= 0x40; } // if emhpasizing r, add 0x40 to the index into the palette LUT.\n                if (PPU_Mask_EmphasizeGreen) { emphasis |= 0x80; } // if emhpasizing g, add 0x80 to the index into the palette LUT.\n                if (PPU_Mask_EmphasizeBlue) { emphasis |= 0x100; } // if emhpasizing b, add 0x100 to the index into the palette LUT.\n                int scanline0OddFrameOffset = 0;\n                if (PPU_Scanline == 0 && PPU_OddFrame && (PPU_Mask_ShowBackground || PPU_Mask_ShowSprites))\n                {\n                    scanline0OddFrameOffset = 1;\n                }\n                if (!PPU_DecodeSignal)\n                {\n                    if (!PPU_ShowScreenBorders)\n                    {\n                        if (scanline0OddFrameOffset == 1 && PPU_Dot == 4)\n                        {\n                            // do nothing. This would be off screen.\n                        }\n                        else\n                        {\n                            Screen.SetPixel(PPU_Dot - 4 - scanline0OddFrameOffset, PPU_Scanline, unchecked((int)NesPalInts[chosenColor | emphasis])); // this sets the pixel on screen to the chosen color.\n                        }\n                    }\n                    else\n                    {\n                        Screen.SetPixel(PPU_Dot - 4 - scanline0OddFrameOffset, PPU_Scanline, unchecked((int)NesPalInts[chosenColor | emphasis])); // this sets the pixel on screen to the chosen color.\n                    }\n                }\n                else\n                {\n                    if (PPU_Mask_Greyscale) // if the ppu greyscale mode is active,\n                    {\n                        chosenColor &= 0x30; //To force greyscale, bitwise AND this color with 0x30\n                    }\n                    PPU_SignalDecode(chosenColor | emphasis);\n                    PrevPrevPrevPrevDotColor = chosenColor | emphasis;\n                }\n            }\n            if (PPU_Scanline == 0 && PPU_OddFrame && (PPU_Mask_ShowBackground || PPU_Mask_ShowSprites) && PPU_Dot == 259)\n            {\n                // draw the backdrop.\n                chosenColor = PaletteRAM[0];\n                // emphasis bits\n                int emphasis = 0;\n                if (PPU_Mask_EmphasizeRed) { emphasis |= 0x40; } // if emhpasizing r, add 0x40 to the index into the palette LUT.\n                if (PPU_Mask_EmphasizeGreen) { emphasis |= 0x80; } // if emhpasizing g, add 0x80 to the index into the palette LUT.\n                if (PPU_Mask_EmphasizeBlue) { emphasis |= 0x100; } // if emhpasizing b, add 0x100 to the index into the palette LUT.\n                if (!PPU_DecodeSignal)\n                {\n                    Screen.SetPixel(255, PPU_Scanline, unchecked((int)NesPalInts[chosenColor | emphasis])); // this sets the pixel on screen to the chosen color.\n                }\n                else\n                {\n                    if (PPU_Mask_Greyscale) // if the ppu greyscale mode is active,\n                    {\n                        chosenColor &= 0x30; //To force greyscale, bitwise AND this color with 0x30\n                    }\n                    PPU_SignalDecode(chosenColor | emphasis);\n                    PrevPrevPrevPrevDotColor = chosenColor | emphasis;\n                }\n            }\n        }\n\n        void DrawToBorderedScreen()\n        {\n\n            int dot = PPU_Dot;\n            int scanline = PPU_Scanline;\n            int emphasis = 0;\n\n            dot -= 3;\n            if (dot < 0)\n            {\n                dot = 341 + dot;\n                scanline--;\n                if (scanline < 0)\n                {\n                    scanline = 261;\n                }\n            }\n\n            int boarderedDot = 0;\n            int boarderedScanline = scanline;\n\n            if (PPU_ShowScreenBorders && dot == 325)\n            {\n                ntsc_signal_of_dot_0 = ntsc_signal;\n            }\n            if (PPU_DecodeSignal && dot == 277)\n            {\n                RenderNTSCScanline();\n            }\n\n            if (scanline < 241 || ((scanline == 241 && dot < 277)) || scanline == 261)\n            {\n\n                if (dot >= 1 && dot <= 256) // visible pixels.\n                {\n                    if (scanline == 261)\n                    {\n                        chosenColor = 0x0F;\n                    }\n                    else\n                    {\n\n                        chosenColor = PrevPrevPrevDotColor;\n\n                        if (PPU_Mask_Greyscale) // if the ppu greyscale mode is active,\n                        {\n                            chosenColor &= 0x30; //To force greyscale, bitwise AND this color with 0x30\n                        }\n                        // emphasis bits\n                        if (PPU_Mask_EmphasizeRed) { emphasis |= 0x40; } // if emhpasizing r, add 0x40 to the index into the palette LUT.\n                        if (PPU_Mask_EmphasizeGreen) { emphasis |= 0x80; } // if emhpasizing g, add 0x80 to the index into the palette LUT.\n                        if (PPU_Mask_EmphasizeBlue) { emphasis |= 0x100; } // if emhpasizing b, add 0x100 to the index into the palette LUT.\n                    }\n                    boarderedDot = dot + 64;\n                    boarderedScanline = scanline;\n                }\n                else if (dot >= 257 && dot <= 267) // right boarder\n                {\n                    if (scanline == 261)\n                    {\n                        chosenColor = 0x0F;\n                    }\n                    else\n                    {\n                        // backdrop.\n                        chosenColor = PrevPrevPrevDotColor;\n                        if (PPU_Mask_Greyscale) // if the ppu greyscale mode is active,\n                        {\n                            chosenColor &= 0x30; //To force greyscale, bitwise AND this color with 0x30\n                        }\n                        // emphasis bits\n                        if (PPU_Mask_EmphasizeRed) { emphasis |= 0x40; } // if emhpasizing r, add 0x40 to the index into the palette LUT.\n                        if (PPU_Mask_EmphasizeGreen) { emphasis |= 0x80; } // if emhpasizing g, add 0x80 to the index into the palette LUT.\n                        if (PPU_Mask_EmphasizeBlue) { emphasis |= 0x100; } // if emhpasizing b, add 0x100 to the index into the palette LUT.\n                    }\n                    boarderedDot = dot + 64;\n                    boarderedScanline = scanline;\n                }\n                else if (dot >= 268 && dot <= 276) // front porch \n                {\n                    // black.\n                    chosenColor = 0x0F;\n                    boarderedDot = dot + 64;\n                    boarderedScanline = scanline;\n                }\n                else if (dot >= 277 && dot <= 301) // horizontal sync \n                {\n                    // black.\n                    chosenColor = 0x0F;\n                    boarderedDot = dot - 277;\n                    boarderedScanline = scanline + 1;\n                }\n                else if (dot >= 302 && dot <= 305) // back porch \n                {\n                    // black.\n                    chosenColor = 0x0F;\n                    boarderedDot = dot - 277;\n                    boarderedScanline = scanline + 1;\n                }\n                else if (dot >= 306 && dot <= 320) // colorburst \n                {\n                    // extremely dark olive.\n                    chosenColor = Signal_COLORBURST;\n                    boarderedDot = dot - 277;\n                    boarderedScanline = scanline + 1;\n                }\n                else if (dot >= 321 && dot <= 325) // back porch \n                {\n                    // black.\n                    chosenColor = 0x0F;\n                    boarderedDot = dot - 277;\n                    boarderedScanline = scanline + 1;\n                }\n                else if (dot == 326) // pulse  \n                {\n\n                    // backdrop in greyscale\n                    if (ThisDotReadFromPaletteRAM)\n                    {\n                        chosenColor = PrevPrevPrevDotColor;\n                    }\n                    else\n                    {\n                        chosenColor = PrevPrevPrevDotColor & 0x30;\n                    }\n\n                    // emphasis bits\n                    if (PPU_Mask_EmphasizeRed) { emphasis |= 0x40; } // if emhpasizing r, add 0x40 to the index into the palette LUT.\n                    if (PPU_Mask_EmphasizeGreen) { emphasis |= 0x80; } // if emhpasizing g, add 0x80 to the index into the palette LUT.\n                    if (PPU_Mask_EmphasizeBlue) { emphasis |= 0x100; } // if emhpasizing b, add 0x100 to the index into the palette LUT.\n\n                    boarderedDot = dot - 277;\n                    boarderedScanline = scanline + 1;\n                }\n                else // right boarder\n                {\n                    // backdrop.\n                    if (scanline == 261 && dot == 0)\n                    {\n                        chosenColor = 0x0F;\n                    }\n                    else\n                    {\n                        chosenColor = PrevPrevPrevDotColor;\n\n                        if (PPU_Mask_Greyscale) // if the ppu greyscale mode is active,\n                        {\n                            chosenColor &= 0x30; //To force greyscale, bitwise AND this color with 0x30\n                        }\n                        // emphasis bits\n                        if (PPU_Mask_EmphasizeRed) { emphasis |= 0x40; } // if emhpasizing r, add 0x40 to the index into the palette LUT.\n                        if (PPU_Mask_EmphasizeGreen) { emphasis |= 0x80; } // if emhpasizing g, add 0x80 to the index into the palette LUT.\n                        if (PPU_Mask_EmphasizeBlue) { emphasis |= 0x100; } // if emhpasizing b, add 0x100 to the index into the palette LUT.\n                    }\n                    if (dot != 0)\n                    {\n                        boarderedDot = dot - 277;\n                        boarderedScanline = scanline + 1;\n\n                    }\n                    else\n                    {\n                        boarderedDot = dot + 64;\n                        boarderedScanline = scanline;\n                    }\n                }\n            }\n            else\n            {\n                if (scanline >= 245 && scanline <= 247)\n                {\n                    // black.\n                    chosenColor = 0x0F;\n                    if (dot >= 277)\n                    {\n                        boarderedDot = dot - 277;\n                        boarderedScanline = scanline + 1;\n                    }\n                    else\n                    {\n                        boarderedDot = dot + 64;\n                        boarderedScanline = scanline;\n                    }\n                }\n                else\n                {\n                    // colorburst happens on this line too.\n                    if (dot >= 306 && dot <= 320) // colorburst \n                    {\n                        // extremely dark olive.\n                        chosenColor = Signal_COLORBURST;\n                        boarderedDot = dot - 277;\n                        boarderedScanline = scanline + 1;\n                    }\n                    else\n                    {\n                        // black.\n                        chosenColor = 0x0F;\n                        if (dot >= 277)\n                        {\n                            boarderedDot = dot - 277;\n                            boarderedScanline = scanline + 1;\n                        }\n                        else\n                        {\n                            boarderedDot = dot + 64;\n                            boarderedScanline = scanline;\n                        }\n                    }\n                }\n            }\n            if (PPU_Scanline == 0 && PPU_OddFrame && (PPU_Mask_ShowBackground || PPU_Mask_ShowSprites) && PPU_Dot < 277)\n            {\n                boarderedDot--;\n            }\n            if (boarderedScanline == 0x106)\n            {\n                boarderedScanline = 0;\n            }\n            if (PPU_DecodeSignal)\n            {\n                PPU_SignalDecode(chosenColor | emphasis);\n            }\n            else\n            {\n                BorderedScreen.SetPixel(boarderedDot, boarderedScanline, unchecked((int)NesPalInts[chosenColor | emphasis])); // this sets the pixel on screen to the chosen color.\n            }\n        }\n\n\n        public bool PPU_DecodeSignal;\n        public bool PPU_ShowScreenBorders;\n        static float[] Voltages =\n            { 0.228f, 0.312f, 0.552f, 0.880f, // Signal low\n\t\t        0.616f, 0.840f, 1.100f, 1.100f, // Signal high\n\t\t        0.192f, 0.256f, 0.448f, 0.712f, // Signal low, attenuated\n\t\t        0.500f, 0.676f, 0.896f, 0.896f  // Signal high, attenuated\n\t\t        };\n        public byte ntsc_signal;\n        public byte ntsc_signal_of_dot_0;\n        public float[] NTSC_Samples = new float[257 * 8 + 24];\n        public float[] Bordered_NTSC_Samples = new float[341 * 8 + 24];\n        static float[] Levels =\n            {\n            (Voltages[0] - Voltages[1]) / (Voltages[6] - Voltages[1]) / 12f,\n            (Voltages[1] - Voltages[1]) / (Voltages[6] - Voltages[1]) / 12f,\n            (Voltages[2] - Voltages[1]) / (Voltages[6] - Voltages[1]) / 12f,\n            (Voltages[3] - Voltages[1]) / (Voltages[6] - Voltages[1]) / 12f,\n            (Voltages[4] - Voltages[1]) / (Voltages[6] - Voltages[1]) / 12f,\n            (Voltages[5] - Voltages[1]) / (Voltages[6] - Voltages[1]) / 12f,\n            (Voltages[6] - Voltages[1]) / (Voltages[6] - Voltages[1]) / 12f,\n            (Voltages[7] - Voltages[1]) / (Voltages[6] - Voltages[1]) / 12f,\n            (Voltages[8] - Voltages[1]) / (Voltages[6] - Voltages[1]) / 12f,\n            (Voltages[9] - Voltages[1]) / (Voltages[6] - Voltages[1]) / 12f,\n            (Voltages[10] - Voltages[1]) / (Voltages[6] - Voltages[1]) / 12f,\n            (Voltages[11] - Voltages[1]) / (Voltages[6] - Voltages[1]) / 12f,\n            (Voltages[12] - Voltages[1]) / (Voltages[6] - Voltages[1]) / 12f,\n            (Voltages[13] - Voltages[1]) / (Voltages[6] - Voltages[1]) / 12f,\n            (Voltages[14] - Voltages[1]) / (Voltages[6] - Voltages[1]) / 12f,\n            (Voltages[15] - Voltages[1]) / (Voltages[6] - Voltages[1]) / 12f\n        };\n        float Saturation = 0.75f;\n        int SignalBufferWidth = 12;\n        static double hue = 0;\n        static float chroma_saturation_correction = 2.4f;\n        static double[] SinTable =\n            {\n            Math.Sin(Math.PI* (0 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Sin(Math.PI* (1 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Sin(Math.PI* (2 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Sin(Math.PI* (3 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Sin(Math.PI* (4 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Sin(Math.PI* (5 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Sin(Math.PI* (6 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Sin(Math.PI* (7 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Sin(Math.PI* (8 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Sin(Math.PI* (9 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Sin(Math.PI* (10 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Sin(Math.PI* (11 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction\n             };\n        static double[] CosTable =\n            {\n            Math.Cos(Math.PI* (0 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Cos(Math.PI* (1 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Cos(Math.PI* (2 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Cos(Math.PI* (3 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Cos(Math.PI* (4 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Cos(Math.PI* (5 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Cos(Math.PI* (6 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Cos(Math.PI* (7 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Cos(Math.PI* (8 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Cos(Math.PI* (9 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Cos(Math.PI* (10 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction,\n            Math.Cos(Math.PI* (11 + 3 - 0.5 + hue) / 6) * chroma_saturation_correction\n             };\n        bool InColorPhase(int col, int DecodePhase)\n        {\n            return (col + DecodePhase) % 12 < 6;\n        }\n        static float ntsc_black = 0.312f, ntsc_white = 1.100f;\n        static int Signal_COLORBURST = 512;\n        static int Signal_SYNC = 513;\n        static float Colorburst_High = (0.524f - Voltages[1]) / (Voltages[6] - Voltages[1]) / 12f;\n        static float Colorburst_Low = (0.148f - Voltages[1]) / (Voltages[6] - Voltages[1]) / 12f;\n\n        void PPU_SignalDecode(int nesColor)\n        {\n            bool boardered = PPU_ShowScreenBorders;\n            byte phase = ntsc_signal;\n            int i = 0;\n            while (i < 8)\n            {\n                float sample = 0;\n                // Decode the NES color.\n                if (nesColor == Signal_COLORBURST)\n                {\n                    sample = InColorPhase(0x8, phase) ? Colorburst_High : Colorburst_Low;\n                }\n                else\n                {\n                    int colInd = (nesColor & 0x0F);   // 0..15 \"cccc\"\n                    int level = (nesColor >> 4) & 3;  // 0..3  \"ll\"\n                    int emphasis = (nesColor >> 6);   // 0..7  \"eee\"\n                    if (colInd > 13) { level = 1; }   // For colors 14..15, level 1 is forced.\n                    int attenuation = (\n                                ((((emphasis & 1) != 0) && InColorPhase(0xC, phase)) ||\n                                (((emphasis & 2) != 0) && InColorPhase(0x4, phase)) ||\n                                (((emphasis & 4) != 0) && InColorPhase(0x8, phase))) && (colInd < 0xE)) ? 8 : 0;\n                    float low = Levels[0 + level + attenuation];\n                    float high = Levels[4 + level + attenuation];\n                    if (colInd == 0) { low = high; } // For color 0, only high level is emitted\n                    if (colInd > 12) { high = low; } // For colors 13..15, only low level is emitted\n                    sample = InColorPhase(colInd, phase) ? high : low;\n                }\n                if (boardered)\n                {\n                    int dot = PPU_Dot - 3;\n                    if (dot < 0)\n                    {\n                        dot = 341 + dot;\n                    }\n                    if (dot >= 277)\n                    {\n                        dot -= 277;\n                    }\n                    else\n                    {\n                        dot += 64;\n                    }\n                    if (PPU_Scanline == 0 && PPU_OddFrame && (PPU_Mask_ShowBackground || PPU_Mask_ShowSprites) && PPU_Dot < 277)\n                    {\n                        dot--;\n                    }\n                    Bordered_NTSC_Samples[dot * 8 + i] = sample;\n                }\n                else if (PPU_Dot <= 256 + 3)\n                {\n                    if (PPU_Dot == 0)\n                    {\n                        NTSC_Samples[i] = sample;\n                    }\n                    else\n                    {\n                        NTSC_Samples[(PPU_Dot - 3) * 8 + i] = sample;\n                    }\n                }\n                phase++;\n                phase %= 12;\n                i++;\n            }\n        }\n        public bool PPU_ShowRawNTSCSignal;\n\n        void RenderNTSCScanline()\n        {\n            byte phase = ntsc_signal_of_dot_0;\n            bool bordered = PPU_ShowScreenBorders; // this value could change at any moment, so it would be nice to avoid errors due to array lengths.\n\n            int scanline0OddFrameOffset = 0;\n            if (PPU_Scanline == 0 && PPU_OddFrame && (PPU_Mask_ShowBackground || PPU_Mask_ShowSprites) && !bordered)\n            {\n                scanline0OddFrameOffset = 8;\n            }\n\n            int width = bordered ? BorderedNTSCScreen.Width : NTSCScreen.Width;\n\n            int i = 0;\n            while (i < width + scanline0OddFrameOffset)\n            {\n                double R = 0;\n                double G = 0;\n                double B = 0;\n                if (!PPU_ShowRawNTSCSignal)\n                {\n                    int center = i + 8;\n                    int begin = center - 6;\n                    int end = center + 6;\n                    double Y = 0;\n                    double U = 0;\n                    double V = 0;\n                    for (int p = begin; p < end; ++p) // Collect and accumulate samples\n                    {\n                        float sample = bordered ? (Bordered_NTSC_Samples[p]) : (NTSC_Samples[p]);\n                        Y += sample;\n                        int rotation = (phase + p) % 12;\n                        U += (sample * SinTable[rotation]);\n                        V += (sample * CosTable[rotation]);\n                    }\n\n                    //U *= (0.35355339 * 2);\n                    //V *= (0.35355339 * 2);\n\n                    U = U * 0.5f + 0.5f;\n                    V = V * 0.5f + 0.5f;\n\n                    bool DebugYUV = false;\n                    if (DebugYUV)\n                    {\n                        Y = 0.5;\n                        U = (i + 0.0f) / width;\n                        V = 1 - (PPU_Scanline / 240f);\n\n                        U -= 0.5f;\n                        V -= 0.5f;\n\n                        U *= (0.35355339 * 2);\n                        V *= (0.35355339 * 2);\n\n                        U += 0.5f;\n                        V += 0.5f;\n                    }\n\n                    // convert YUV to RGB\n                    R = 1.164 * (Y - 16 / 256.0) + 1.596 * (V - 128 / 256.0);\n                    G = 1.164 * (Y - 16 / 256.0) - 0.392 * (U - 128 / 256.0) - 0.813 * (V - 128 / 256.0);\n                    B = 1.164 * (Y - 16 / 256.0) + 2.017 * (U - 128 / 256.0);\n\n                    // other values ?\n                    //double R = 1.164 * (Y - 16 / 256.0) + 1.14 * (V - 128 / 256.0);\n                    //double G = 1.164 * (Y - 16 / 256.0) - (1 / 1.14) * (U - 128 / 256.0) - (1 / (1.14 * 1.78)) * (V - 128 / 256.0);\n                    //double B = 1.164 * (Y - 16 / 256.0) + (1.14 * 1.78) * (U - 128 / 256.0);\n\n                    // convert YUV to normalized RGB\n                    //double R = 1.164 * (Y - 16 / 256.0) + 1 * (V - 128 / 256.0);\n                    //double G = 1.164 * (Y - 16 / 256.0) - 0.31764705882 * (U - 128 / 256.0) - 0.68359375 * (V - 128 / 256.0);\n                    //double B = 1.164 * (Y - 16 / 256.0) + 1 * (U - 128 / 256.0);\n\n                    if (R < 0) { R = 0; }\n                    if (R > 1) { R = 1; }\n                    if (G < 0) { G = 0; }\n                    if (G > 1) { G = 1; }\n                    if (B < 0) { B = 0; }\n                    if (B > 1) { B = 1; }\n                }\n                if (PPU_ShowScreenBorders)\n                {\n                    if (PPU_ShowRawNTSCSignal)\n                    {\n                        R = Bordered_NTSC_Samples[i] * 12;\n                        G = Bordered_NTSC_Samples[i] * 12;\n                        B = Bordered_NTSC_Samples[i] * 12;\n                        if (R < 0) { R = 0; }\n                        if (R > 1) { R = 1; }\n                        if (G < 0) { G = 0; }\n                        if (G > 1) { G = 1; }\n                        if (B < 0) { B = 0; }\n                        if (B > 1) { B = 1; }\n                    }\n                    BorderedNTSCScreen.SetPixel(i, PPU_Scanline, Color.FromArgb((byte)(R * 255), (byte)(G * 255), (byte)(B * 255))); // this sets the pixel on screen to the chosen color. \n                }\n                else\n                {\n                    if (PPU_ShowRawNTSCSignal)\n                    {\n                        R = NTSC_Samples[i + 8] * 12;\n                        G = NTSC_Samples[i + 8] * 12;\n                        B = NTSC_Samples[i + 8] * 12;\n                        if (R < 0) { R = 0; }\n                        if (R > 1) { R = 1; }\n                        if (G < 0) { G = 0; }\n                        if (G > 1) { G = 1; }\n                        if (B < 0) { B = 0; }\n                        if (B > 1) { B = 1; }\n                    }\n                    if (scanline0OddFrameOffset == 0)\n                    {\n                        NTSCScreen.SetPixel(i, PPU_Scanline, Color.FromArgb((byte)(R * 255), (byte)(G * 255), (byte)(B * 255))); // this sets the pixel on screen to the chosen color.\n                    }\n                    else\n                    {\n                        if (i >= 8)\n                        {\n                            NTSCScreen.SetPixel(i - 8, PPU_Scanline, Color.FromArgb((byte)(R * 255), (byte)(G * 255), (byte)(B * 255))); // this sets the pixel on screen to the chosen color.\n                        }\n                    }\n                }\n                i++;\n            }\n        }\n\n        void PPU_MapperSpecificFunctions()\n        {\n            Cart.MapperChip.PPUClock(); // If the mapper chip does something every ppu clock... (See MMC3)\n        }\n\n        // If OAM corruption is pending, it occurs on the first rendered dot.\n        public void CorruptOAM()\n        {\n            // basically 8 entries of OAM are getting replaced (this is considered a single \"row\" of OAM) \n            // PPU_OAMCorruptionIndex is the row that gets corrupted.\n            if (PPU_OAMCorruptionIndex == 0x20)\n            {\n                PPU_OAMCorruptionIndex = 0;\n            }\n            int i = 0;\n            while (i < 8) // 8 entries in a row\n            {\n                OAM[PPU_OAMCorruptionIndex * 8 + i] = OAM[i]; // The corrupted row is replaced with the values from row 0\n                i++;\n            }\n            OAM2[PPU_OAMCorruptionIndex] = OAM2[0]; // Also corrupt this byte.\n            // this all happens in a single cycle.\n        }\n\n\n\n\n\n\n\n        bool OamCorruptedOnOddCycle;\n        public byte PPU_OAMLatch; // is this just the ppubus?\n        public ushort InRangeCheck; // Is this sprite in range of htis scanline?\n        public byte PPU_OAMBuffer; // This is the value read from $2004, updated on half cycles.\n        bool NineObjectsOnThisScanline;\n        void PPU_Render_SpriteEvaluation()\n        {\n            bool SpriteEval_ReadOnly_PreRenderLine = false;\n            if (PPU_Scanline == 261)\n            {\n                SpriteEval_ReadOnly_PreRenderLine = true;\n            }\n            if ((PPU_Mask_ShowBackground_Instant || PPU_Mask_ShowSprites_Instant))\n            {\n                if (PPU_PendingOAMCorruption) // OAM corruption occurs on the visible dot after rendering was enabled. It also can happen on the pre-render line.\n                {\n                    PPU_PendingOAMCorruption = false;\n                    if (!PPU_OAMCorruptionRenderingEnabledOutOfVBlank)\n                    {\n                        CorruptOAM();\n                    }\n                    PPU_OAMCorruptionRenderingEnabledOutOfVBlank = false;\n                }\n            }\n\n            if ((PPU_Dot >= 0 && PPU_Dot <= 64)) // Dots 1 through 64, not on the pre-render line. (and also dot 0 for OAM corruption purposes)\n            {\n\n                // this step is clearing secondary OAM, and writing FF to each byte in the array.\n                if ((PPU_Dot & 1) == 1)\n                { //odd cycles\n                    if ((PPU_Mask_ShowBackground_Delayed || PPU_Mask_ShowSprites_Delayed))\n                    {\n                        if (SpriteEval_ReadOnly_PreRenderLine)\n                        {\n                            PPU_OAMLatch = OAM2[OAM2Address];\n                        }\n                        else\n                        {\n                            PPU_OAMLatch = 0xFF;\n                        }\n                        if (PPU_Dot == 1)\n                        {\n                            OAM2Address = 0; // if this is dot 1, reset the secondary OAM address\n                            SecondaryOAMFull = false;// also reset the flag that checks of secondary OAM is full.\n                                                     // in preparation for the next section, let's clear these flags too\n                            SpriteEvaluationTick = 0;\n                            OAMAddressOverflowedDuringSpriteEvaluation = false;\n                        }\n                        if (PPU_OAMCorruptionRenderingDisabledOutOfVBlank || PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant)\n                        {\n                            PPU_OAMCorruptionRenderingDisabledOutOfVBlank = false;\n                            PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant = false;\n                            PPU_PendingOAMCorruption = true;\n                            PPU_OAMCorruptionIndex = OAM2Address; // this value will be used when rendering is re-enabled and the corruption occurs\n                        }\n                    }\n                }\n                else\n                { //even cycles\n                    if (PPU_Dot > 0)\n                    {\n                        if ((PPU_Mask_ShowBackground_Delayed || PPU_Mask_ShowSprites_Delayed))\n                        {\n                            if (!SpriteEval_ReadOnly_PreRenderLine)\n                            {\n                                OAM2[OAM2Address] = PPU_OAMLatch; // store FF in secondary OAM\n                            }\n                            if (PPU_OAMCorruptionRenderingDisabledOutOfVBlank)\n                            {\n                                PPU_OAMCorruptionRenderingDisabledOutOfVBlank = false;\n                                PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant = false;\n                                PPU_PendingOAMCorruption = true;\n                                PPU_OAMCorruptionIndex = OAM2Address; // this value will be used when rendering is re-enabled and the corruption occurs\n                            }\n\n                            OAM2Address++;  // increment this value so on the next even cycle, we write to the next SecondaryOAM address.\n                            OAM2Address &= 0x1F;  // keep the secondary OAM address in-bounds\n\n                            if (PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant && PPU_Dot == 64)\n                            {\n                                PPU_OAMCorruptionRenderingDisabledOutOfVBlank = false;\n                                PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant = false;\n                                PPU_PendingOAMCorruption = true;\n                            }\n                        }\n                        else\n                        {\n                            if (PPU_OAMCorruptionRenderingDisabledOutOfVBlank || PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant)\n                            {\n                                PPU_OAMCorruptionRenderingDisabledOutOfVBlank = false;\n                                PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant = false;\n                                PPU_PendingOAMCorruption = true;\n                                PPU_OAMCorruptionIndex = OAM2Address; // this value will be used when rendering is re-enabled and the corruption occurs\n                            }\n                        }\n                    }\n                    else\n                    {\n                        OAM2Address++;  // increment this value so on the next even cycle, we write to the next SecondaryOAM address.\n                        OAM2Address &= 0x1F;  // keep the secondary OAM address in-bounds\n                    }\n                }\n            }\n            else if ((PPU_Dot >= 65 && PPU_Dot <= 256)) // Dots 65 through 256, not on the pre-render line\n            {\n                if (PPU_Dot == 65)\n                {\n                    OAM2Address = 0;\n                    NineObjectsOnThisScanline = false;\n                }\n                if (PPU_Mask_ShowBackground_Instant || PPU_Mask_ShowSprites_Instant || PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant) // if rendering is enabled, or was *just* disabled mid evaluation\n                {\n                    if ((PPU_Dot & 1) == 1)\n                    { //odd cycles\n                        byte PrevSpriteEvalTemp = PPU_OAMLatch;\n                        PPU_OAMLatch = OAM[PPUOAMAddress]; // read from OAM\n                        if ((PPUOAMAddress & 3) == 2)\n                        {\n                            PPU_OAMLatch &= 0xE7; // OAM address 02, 06, 0A, 0E, 12... are missing bits 3 and 4.\n                        }\n\n                        // If rendering was disabled *this* cycle (the odd cycle) then the even cycle will run normally, and the *next odd cycle* will have the OAM address increment. Presumably, that's when we record secondOAMAddr.\n                        if (PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant)\n                        {\n                            PPU_OAMEvaluationCorruptionOddCycle = false;\n                            PPU_OAMCorruptionRenderingDisabledOutOfVBlank = false;\n                            if (!SpriteEval_ReadOnly_PreRenderLine)\n                            {\n                                PPUOAMAddress++;\n                            }\n                            OamCorruptedOnOddCycle = true;\n\n                        }\n                    }\n                    else\n                    { //even cycles                       \n                        if (!OAMAddressOverflowedDuringSpriteEvaluation)\n                        {\n                            byte PreIncVal = PPUOAMAddress; // for checking if PPUOAMAddress overflows\n                            if (!SecondaryOAMFull && !SpriteEval_ReadOnly_PreRenderLine) // If secondary OAM is not yet full,\n                            {\n                                OAM2[OAM2Address] = PPU_OAMLatch; // store this value at the secondary oam address.\n                            }\n                            byte OAM2READ = OAM2[OAM2Address];\n                            if (SpriteEvaluationTick == 0) // tick 0: check if this object's y position is in range for this scanline\n                            {\n                                PPU_OAMEvaluationObjectInXRange = false;\n                                InRangeCheck = (ushort)((PPU_Scanline & 0xFF) - PPU_OAMLatch);\n                                if (!NineObjectsOnThisScanline && !SpriteEval_ReadOnly_PreRenderLine && InRangeCheck < (PPU_Spritex16 ? 16 : 8))\n                                {\n                                    PPU_OAMEvaluationObjectInRange = true;\n                                    // if this sprite is within range.\n                                    if (!SecondaryOAMFull)\n                                    {\n                                        if (!OamCorruptedOnOddCycle)\n                                        {\n                                            if (!SpriteEval_ReadOnly_PreRenderLine)\n                                            {\n                                                PPUOAMAddress++; // +1\n                                            }\n                                            OAM2Address++; // increment this for the next write to secondary OAM\n                                        }\n                                        if (!SecondaryOAMFull) // if secondary OAM is not full\n                                        {\n                                            OAM2Address &= 0x1F; // keep the secondary OAM address in-bounds\n                                            if (OAM2Address == 0) // If we've overflowed the secondary OAM address\n                                            {\n                                                SecondaryOAMFull = true; // secondary OAM is now full.\n                                            }\n                                        }\n                                        // Sprite zero hits actually have nothing to do with reading the object at OAM index 0. Rather, if an object is within range of the scanline on dot 66.\n                                        // typically, the object processed on dot 66 is OAM[0], though it's possible using precisely timed writes to $2003 to have PPUOAMAddress start processing here from a different value.\n                                        if (PPU_Dot == 66)\n                                        {\n                                            PPU_NextScanlineContainsSpriteZero = true; // this value will be transferred to PPU_PreviousScanlineContainsSpriteZero at the end of the scanline, and that variable is used in sp 0 hit detection.\n                                        }\n                                    }\n                                    else\n                                    {\n                                        NineObjectsOnThisScanline = true;\n                                        PPUOAMAddress++;\n                                        if (!PPUStatus_SpriteOverflow)// if secondary OAM is full, yet another object is on this scanline\n                                        {\n                                            PPUStatus_SpriteOverflow = true; // set the sprite overflow flag\n                                        }\n                                    }\n                                    if (!SpriteEval_ReadOnly_PreRenderLine)\n                                    {\n                                        SpriteEvaluationTick++; // increment the tick for next even ppu cycle.\n                                    }\n                                }\n                                else\n                                {\n                                    if (PPU_Dot == 66)\n                                    {\n                                        PPU_NextScanlineContainsSpriteZero = false; // this value will be transferred to PPU_PreviousScanlineContainsSpriteZero at the end of the scanline, and that variable is used in sp 0 hit detection.\n                                    }\n                                    PPU_OAMEvaluationObjectInRange = false;\n                                    if (!OamCorruptedOnOddCycle && !SpriteEval_ReadOnly_PreRenderLine)\n                                    {\n                                        if (SecondaryOAMFull && !NineObjectsOnThisScanline)// this behavior stops after finding the ninth object.\n                                        {\n                                            if ((PPUOAMAddress & 0x3) == 3)\n                                            {\n                                                PPUOAMAddress++; // A real hardware bug.\n                                            }\n                                            else\n                                            {\n                                                PPUOAMAddress += 4; // +4\n                                                PPUOAMAddress++; // A real hardware bug.\n                                            }\n                                        }\n                                        else\n                                        {\n                                            PPUOAMAddress += 4; // +4\n                                            PPUOAMAddress &= 0xFC; // also mask away the lower 2 bits\n                                        }\n                                    }\n                                }\n                            }\n                            else // ticks 1, 2, or 3\n                            {\n                                if (SpriteEvaluationTick == 3) // tick 3: X position.\n                                {\n                                    PPU_OAMEvaluationObjectInRange = false;\n                                    // OAM X coordinate.\n                                    // This also runs the \"vertical in range check\", though typically the result doesn't matter.\n                                    if (PPU_Scanline - PPU_OAMLatch >= 0 && PPU_Scanline - PPU_OAMLatch < (PPU_Spritex16 ? 16 : 8))\n                                    {\n                                        // if this sprite is within range.\n                                        PPU_OAMEvaluationObjectInXRange = true;\n                                        if (!SecondaryOAMFull)\n                                        {\n                                            if (!OamCorruptedOnOddCycle && !SpriteEval_ReadOnly_PreRenderLine)\n                                            {\n                                                PPUOAMAddress++; // +1\n                                            }\n                                        }\n                                        else\n                                        {\n                                            if (!OamCorruptedOnOddCycle && !SpriteEval_ReadOnly_PreRenderLine)\n                                            {\n                                                PPUOAMAddress += 4; // +1 (In theory, this should be +4, though my experiments only reflect my consoles behavior if this is +1?)\n                                            }\n                                        }\n                                    }\n                                    else\n                                    {\n                                        PPU_OAMEvaluationObjectInXRange = false;\n                                        if (!SecondaryOAMFull)\n                                        {\n                                            if (!OamCorruptedOnOddCycle && !SpriteEval_ReadOnly_PreRenderLine)\n                                            {\n                                                PPUOAMAddress += 1; // +1 (In theory, this should be +4, though my experiments only reflect my consoles behavior if this is +1?)\n                                                PPUOAMAddress &= 0xFC; // also mask away the lower 2 bits\n                                            }\n                                        }\n                                        else\n                                        {\n                                            PPUOAMAddress += 1; // +1 (In theory, this should be +4, though my experiments only reflect my consoles behavior if this is +1?)\n                                            PPUOAMAddress &= 0xFC; // also mask away the lower 2 bits\n                                        }\n                                    }\n                                }\n                                else // ticks 1 and 2 don't make any checks. Only increment the OAM address.\n                                {\n                                    if (!OamCorruptedOnOddCycle && !SpriteEval_ReadOnly_PreRenderLine)\n                                    {\n                                        PPUOAMAddress++; // +1\n                                    }\n                                }\n                                SpriteEvaluationTick++; // increment the tick for next even ppu cycle.\n                                SpriteEvaluationTick &= 3; // and reset the tick to 0 if it reaches 4.\n                                if (!SecondaryOAMFull && !SpriteEval_ReadOnly_PreRenderLine) // if secondary OAM is not full\n                                {\n                                    OAM2Address++; // increment the secondary OAM address.\n                                    OAM2Address &= 0x1F; // keep the secondary OAM address in-bounds\n                                    if (OAM2Address == 0) // If we've overflowed the secondary OAM address\n                                    {\n                                        SecondaryOAMFull = true; // secondary OAM is now full.\n                                    }\n                                }\n                            }\n                            OamCorruptedOnOddCycle = false;\n\n                            if (PPUOAMAddress < PreIncVal && PPUOAMAddress < 4) // If an overflow occured\n                            {\n                                OAMAddressOverflowedDuringSpriteEvaluation = true; // set this flag.\n                            }\n                            PPU_OAMLatch = OAM2READ; // When overflowed, the ppu reads instead of writing to OAM2. (Run this regardless of if OAM2 is full or not.)\n                        }\n                        else\n                        {   // OAM Address Overflowed During Sprite Evaluation\n                            // fail to write to SecondaryOAM\n                            // boo womp.\n\n                            // also update the PPUOAMAddress.\n                            if (!OamCorruptedOnOddCycle && !SpriteEval_ReadOnly_PreRenderLine)\n                            {\n                                PPUOAMAddress += 4; // +4\n                                PPUOAMAddress &= 0xFC; // also mask away the lower 2 bits\n                            }\n                            PPU_OAMLatch = OAM2[OAM2Address]; // When overflowed, the ppu reads instead of writing to OAM2.\n                        }\n                        if (PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant && !PPU_OAMEvaluationCorruptionOddCycle) // if we just disabled rendering mid OAM evaluation, the address is incremented yet again.\n                        {\n                            PPU_OAMCorruptionRenderingDisabledOutOfVBlank = false;\n                            PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant = false;\n                            PPU_PendingOAMCorruption = true;\n\n                            if ((OAM2Address & 3) != 0 && !OAMAddressOverflowedDuringSpriteEvaluation && !SpriteEval_ReadOnly_PreRenderLine)\n                            {\n                                OAM2Address &= 0xFC;\n                                OAM2Address += 4;\n                            }\n                            if (PPUClock == 0 || PPUClock == 3)\n                            {\n                                PPU_OAMCorruptionIndex = (byte)(OAM2Address); // this value will be used when rendering is re-enabled and the corruption occurs\n                            }\n                            if (PPUClock == 1 || PPUClock == 2)\n                            {\n                                PPU_OAMCorruptionIndex = (byte)(OAM2Address); // this value will be used when rendering is re-enabled and the corruption occurs\n                            }\n                            if (PPU_Dot == 256)\n                            {\n                                PPU_OAMCorruptionIndex = OamCorruptedOnOddCycle ? (byte)0 : (byte)1; //I have no idea.\n                            }\n\n                        }\n                        PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant = false;\n                    }\n                }\n\n            }\n            else if (PPU_Dot >= 257 && PPU_Dot <= 320) // this also happens on the pre-render line.\n            {\n                PPU_CurrentScanlineContainsSpriteZero = PPU_NextScanlineContainsSpriteZero;\n\n                if ((PPU_Mask_ShowBackground_Delayed || PPU_Mask_ShowSprites_Delayed))\n                {\n                    PPUOAMAddress = 0; // this is reset during every one of these cycles, 257 through 320\n                }\n                if (PPU_Dot == 257)\n                {\n                    // reset these flags for this section.\n                    OAM2Address = 0;\n                    SpriteEvaluationTick = 0;\n                }\n\n                if (PPU_OAMCorruptionRenderingDisabledOutOfVBlank && (PPUClock == 0 || PPUClock == 3))\n                {\n                    PPU_OAMCorruptionRenderingDisabledOutOfVBlank = false;\n                    PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant = false;\n                    PPU_PendingOAMCorruption = true;\n                    PPU_OAMCorruptionIndex = OAM2Address; // this value will be used when rendering is re-enabled and the corruption occurs\n                }\n\n                if (PPU_READ)\n                {\n                    Cart.Emu.PPU_OctalLatch = (byte)PPU_AddressBus;\n                }\n\n                switch (SpriteEvaluationTick)\n                {\n                    // So each scanline can only have up to 8 sprites.\n                    // Each sprite has a Y position, Pattern, Attributes, and X position.\n                    // So there's an 8-index-long array for each of those.\n                    // Each index in the array is for a different sprite.\n\n                    // Sprites also have 2 \"bit plane\" shift registers.\n                    // These are the 8 pixels to draw for the object on this scanline.\n                    // Again, there are 8 objects, so there are 2 8-index-long arrays of bit planes.\n\n                    // each case is a different ppu cycle.\n                    // case 0.\n                    // next cycle, case 1.\n                    // next cycle, case 2, and so on.\n                    // case 7 then leads back to case 0.\n\n                    case 0: // Y position         dot 257, (+8), (+16) ...\n                        if (PPU_Mask_ShowBackground_Delayed || PPU_Mask_ShowSprites_Delayed) // if rendering has been enabled for at least one cycle\n                        {\n                            // set this object's Y position in the array\n                            PPU_OAMLatch = OAM2[OAM2Address]; // Updating PPU_SpriteEvaluationTemp so reading from $2004 works properly.\n                            PPU_SpriteYposition[OAM2Address / 4] = PPU_OAMLatch;\n\n                            PPU_PatternAddressRegister_NT = (ushort)(0x2000 + (PPU_v & 0x0FFF));\n                            PPU_PAR_MUX = PPU_PatternAddressRegister_NT;\n                            PPU_AddressBus = PPU_PAR_MUX;\n\n                            InRangeCheck = (ushort)((PPU_Scanline & 0xFF) - PPU_OAMLatch);\n                        }\n                        OAM2Address++; // and increment the Secondary OAM address for next cycle\n                        break;\n                    case 1: // Pattern            dot 258, (+8), (+16) ...\n                        if (PPU_Mask_ShowBackground_Delayed || PPU_Mask_ShowSprites_Delayed) // if rendering has been enabled for at least one cycle\n                        {\n                            // set this object's pattern in the array\n                            PPU_OAMLatch = OAM2[OAM2Address]; // Updating PPU_SpriteEvaluationTemp so reading from $2004 works properly.\n                            PPU_SpritePattern[OAM2Address / 4] = PPU_OAMLatch;\n                            PPU_Render_ShiftRegistersAndBitPlanes(); // Dummy Nametable Fetch\n                        }\n                        OAM2Address++; // and increment the Secondary OAM address for next cycle\n                        break;\n                    case 2: // Attribute          dot 259, (+8), (+16) ...\n                        if (PPU_Mask_ShowBackground_Delayed || PPU_Mask_ShowSprites_Delayed) // if rendering has been enabled for at least one cycle\n                        {\n                            // set this object's attribute in the array\n                            PPU_OAMLatch = OAM2[OAM2Address]; // Updating PPU_SpriteEvaluationTemp so reading from $2004 works properly.\n                            PPU_SpriteAttribute[OAM2Address / 4] = PPU_OAMLatch;\n\n                            PPU_PatternAddressRegister_NT = (ushort)(0x2000 + (PPU_v & 0x0FFF));\n                            PPU_PAR_MUX = PPU_PatternAddressRegister_NT;\n                            PPU_AddressBus = PPU_PAR_MUX;\n                        }\n                        OAM2Address++; // and increment the Secondary OAM address for next cycle\n                        break;\n                    case 3: // X position         dot 260, (+8), (+16) ...\n                        if (PPU_Mask_ShowBackground_Delayed || PPU_Mask_ShowSprites_Delayed) // if rendering has been enabled for at least one cycle\n                        {\n                            // set this object's X position in the array\n                            PPU_OAMLatch = OAM2[OAM2Address]; // Updating PPU_SpriteEvaluationTemp so reading from $2004 works properly.\n                            PPU_SpriteXposition[OAM2Address / 4] = PPU_OAMLatch;\n                            PPU_SpriteShifterCounter[OAM2Address / 4] = PPU_OAMLatch;\n                            PPU_Render_ShiftRegistersAndBitPlanes(); // Dummy Nametable Fetch                            \n                        }\n                        // notably, the secondary OAM address does not get incremented until case 7\n                        break;\n                    case 4: // X position (again) dot 261, (+8), (+16) ...\n                        if (PPU_Mask_ShowBackground_Delayed || PPU_Mask_ShowSprites_Delayed) // if rendering has been enabled for at least one cycle\n                        {\n                            // set this object's X position in the array... again.\n                            PPU_OAMLatch = OAM2[OAM2Address]; // Updating PPU_SpriteEvaluationTemp so reading from $2004 works properly.\n                            PPU_SpriteXposition[OAM2Address / 4] = PPU_OAMLatch;\n                            // But also: Find the PPU address of this sprite's graphical data inside the Pattern Tables.\n                            PPU_SpriteEvaluation_GetSpriteAddress((byte)(OAM2Address / 4));\n                            PPU_CheckPAR();\n                            PPU_PatternAddressRegister_CHR &= 0b1111111110111;\n                            PPU_PAR_MUX = PPU_PatternAddressRegister_CHR;\n                            PPU_AddressBus = PPU_PAR_MUX;\n                        }\n\n                        break;\n                    case 5: // X position (again)  dot 262, (+8), (+16) ...\n                        if (PPU_Mask_ShowBackground_Delayed || PPU_Mask_ShowSprites_Delayed) // if rendering has been enabled for at least one cycle\n                        {\n                            // set this object's X position in the array... again.\n                            PPU_OAMLatch = OAM2[OAM2Address]; // Updating PPU_SpriteEvaluationTemp so reading from $2004 works properly.\n                            PPU_SpriteXposition[OAM2Address / 4] = PPU_OAMLatch;\n                            // but also: set up the bit plane shift register.\n\n                            PPU_AddressBus = (ushort)((PPU_PatternAddressRegister_CHR & 0xFF00) | PPU_OctalLatch);\n\n                            PPU_SpritePatternL = Cart.MapperChip.FetchPPU();\n                            if (((PPU_SpriteAttribute[OAM2Address / 4] >> 6) & 1) == 1) // Attributes are set up to flip X\n                            {\n                                PPU_SpritePatternL = Flip(PPU_SpritePatternL);\n                            }\n                            PPU_SpriteShiftRegisterL[OAM2Address / 4] = PPU_SpritePatternL;\n                        }\n\n                        // in-range check. (The pre-render line ends up checking scanline 5 due to the `& 0xFF`.\n                        if (!(InRangeCheck < (PPU_Spritex16 ? 16 : 8)))\n                        {\n                            PPU_SpriteShiftRegisterL[OAM2Address / 4] = 0; // clear the value in this shift register if this object isn't in range.\n                        }\n\n                        break;\n                    case 6: // X position (again)  dot 263, (+8), (+16) ...\n                        if (PPU_Mask_ShowBackground_Delayed || PPU_Mask_ShowSprites_Delayed) // if rendering has been enabled for at least one cycle\n                        {\n                            // set this object's X position in the array... again.\n                            PPU_OAMLatch = OAM2[OAM2Address]; // Updating PPU_SpriteEvaluationTemp so reading from $2004 works properly.\n                            PPU_SpriteXposition[OAM2Address / 4] = PPU_OAMLatch;\n                            // but also: add 8 to the PPU address. The other bit plane is 8 addresses away.\n                            PPU_SpriteEvaluation_GetSpriteAddress((byte)(OAM2Address / 4)); // we need to recalculate this. Slow, but accurate. (TODO: Can we test for this with a well timed write to $2000?)\n                            PPU_AddressBus |= 8;\n                            PPU_CheckPAR();\n                            PPU_PatternAddressRegister_CHR |= 8;\n                            PPU_PAR_MUX = PPU_PatternAddressRegister_CHR;\n                            PPU_AddressBus = PPU_PAR_MUX;\n                        }\n\n                        break;\n\n                    case 7: // X position (again)  dot 264, (+8), (+16) ...\n                        if (PPU_Mask_ShowBackground_Delayed || PPU_Mask_ShowSprites_Delayed) // if rendering has been enabled for at least one cycle\n                        {\n                            // set this object's X position in the array... again.\n                            PPU_OAMLatch = OAM2[OAM2Address]; // Updating PPU_SpriteEvaluationTemp so reading from $2004 works properly.\n                            PPU_SpriteXposition[OAM2Address / 4] = PPU_OAMLatch; // read X pos again\n                            // but also: set up the second bit plane\n\n                            PPU_AddressBus = (ushort)((PPU_PatternAddressRegister_CHR & 0xFF00) | PPU_OctalLatch);\n\n                            PPU_SpritePatternH = Cart.MapperChip.FetchPPU();\n                            if (((PPU_SpriteAttribute[OAM2Address / 4] >> 6) & 1) == 1) // Attributes are set up to flip X\n                            {\n                                PPU_SpritePatternH = Flip(PPU_SpritePatternH);\n                            }\n                            PPU_SpriteShiftRegisterH[OAM2Address / 4] = PPU_SpritePatternH;\n                        }\n\n                        // in-range check. (The pre-render line ends up checking scanline 5 due to the `& 0xFF`.\n                        if (!(InRangeCheck < (PPU_Spritex16 ? 16 : 8)))\n                        {\n                            PPU_SpriteShiftRegisterH[OAM2Address / 4] = 0; // clear the value in this shift register if this object isn't in range.\n                        }\n\n                        if (PPU_SpriteShiftRegisterH[OAM2Address / 4] != 0)\n                        { \n                        \n                        }\n\n\n                        OAM2Address++; // and increment the Secondary OAM address for next cycle\n\n                        break;\n                }\n                if (PPU_ALE && !PPU_READ)\n                {\n                    Cart.Emu.PPU_OctalLatch = (byte)PPU_AddressBus;\n                }\n                OAM2Address &= 0x1F; // keep the secondary OAM address in-bounds\n\n                SpriteEvaluationTick++; // increment the tick, so next cycle uses the following case in the switch statement\n                SpriteEvaluationTick &= 7; // and reset at 8\n\n                if (PPU_OAMCorruptionRenderingDisabledOutOfVBlank && (PPUClock == 1 || PPUClock == 2))\n                {\n                    PPU_OAMCorruptionRenderingDisabledOutOfVBlank = false;\n                    PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant = false;\n                    PPU_PendingOAMCorruption = true;\n                    PPU_OAMCorruptionIndex = OAM2Address; // this value will be used when rendering is re-enabled and the corruption occurs\n                }\n\n            }\n            else\n            {\n                // cycles 320 to 340\n                if (PPU_OAMCorruptionRenderingDisabledOutOfVBlank || PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant)\n                {\n                    PPU_OAMCorruptionRenderingDisabledOutOfVBlank = false;\n                    PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant = false;\n                    PPU_PendingOAMCorruption = true;\n                    PPU_OAMCorruptionIndex = OAM2Address; // this value will be used when rendering is re-enabled and the corruption occurs\n                }\n\n                if (PPU_Dot == 339)\n                {\n                    for (int i = 0; i < 8; i++)\n                    {\n                        if ((PPU_Mask_ShowSprites || PPU_Mask_ShowBackground))\n                        {\n                        }\n                        else\n                        {\n                            PPU_SpriteShifterCounter[i] = 0;\n                        }\n                    }\n                }\n            }\n            // and that's all for sprite evaluation!\n        }\n\n        void PPU_SpriteEvaluation_GetSpriteAddress(byte SecondOAMSlot)\n        {\n            // PPU_PatternSelect_Sprites is set by writing to bit 3 of address $2000\n\n            if (!PPU_Spritex16) //8x8 sprites\n            {\n                // The address is $0000 or $1000 depending on the nametable.\n                // plus the pattern value from OAM * 16\n                // plus the number of scanlines from the top of the object.\n                // if the attributes are set to flip Y, it's 7 - the number of scanlines from the top of the object.\n                if (((PPU_SpriteAttribute[SecondOAMSlot] >> 7) & 1) == 0) // Attributes are not set up to flip Y\n                {\n                    PPU_AddressBus = (ushort)((PPU_PatternSelect_Sprites ? 0x1000 : 0) + (PPU_SpritePattern[SecondOAMSlot] << 4) + ((PPU_Scanline & 0xFF) - PPU_SpriteYposition[SecondOAMSlot]));\n                }\n                else  // Attributes are set up to flip Y\n                {\n                    PPU_AddressBus = (ushort)((PPU_PatternSelect_Sprites ? 0x1000 : 0) + (PPU_SpritePattern[SecondOAMSlot] << 4) + ((7 - ((PPU_Scanline & 0xFF) - PPU_SpriteYposition[SecondOAMSlot])) & 7));\n                }\n            }\n            else //8x16 sprites\n            {\n                // In 8x16 mode, instead of using PPU_PatternSelect_Sprites to determine which pattern table to fetch data from...\n                // these sprites instead use bit 0 of the object's pattern information from OAM.\n\n                // The address is $0000 or $1000 depending on the nametable.\n                // plus (the pattern value from OAM, clearing bit 0) * 16\n                // plus the number of scanlines from the top of the object.\n                // if the attributes are set to flip Y, it's 7 - the number of scanlines from the top of the object.\n\n                // if we're drawing the bottom half of the sprite, add 16.\n                if (((PPU_SpriteAttribute[SecondOAMSlot] >> 7) & 1) == 0) // Attributes are not set up to flip Y\n                {\n                    if ((PPU_Scanline & 0xFF) - PPU_SpriteYposition[SecondOAMSlot] < 8)\n                    {\n                        PPU_AddressBus = (ushort)((((PPU_SpritePattern[SecondOAMSlot] & 1) == 1) ? 0x1000 : 0) | ((PPU_SpritePattern[SecondOAMSlot] & 0xFE) << 4) + ((PPU_Scanline & 0xFF) - PPU_SpriteYposition[SecondOAMSlot]));\n                    }\n                    else\n                    {\n                        PPU_AddressBus = (ushort)((((PPU_SpritePattern[SecondOAMSlot] & 1) == 1) ? 0x1000 : 0) | (((PPU_SpritePattern[SecondOAMSlot] & 0xFE) << 4) + 16) + (((PPU_Scanline & 0xFF) - PPU_SpriteYposition[SecondOAMSlot]) & 7));\n                    }\n                }\n                else // Attributes are set up to flip Y\n                {\n                    if ((PPU_Scanline & 0xFF) - PPU_SpriteYposition[SecondOAMSlot] < 8)\n                    {\n                        PPU_AddressBus = (ushort)((((PPU_SpritePattern[SecondOAMSlot] & 1) == 1) ? 0x1000 : 0) | (((PPU_SpritePattern[SecondOAMSlot] & 0xFE) << 4) + 16) - (((PPU_Scanline & 0xFF) - PPU_SpriteYposition[SecondOAMSlot]) & 7) + 7);\n                    }\n                    else\n                    {\n                        PPU_AddressBus = (ushort)((((PPU_SpritePattern[SecondOAMSlot] & 1) == 1) ? 0x1000 : 0) | (((PPU_SpritePattern[SecondOAMSlot] & 0xFE) << 4) + 7) - (((PPU_Scanline & 0xFF) - PPU_SpriteYposition[SecondOAMSlot]) & 7));\n                    }\n                }\n            }\n        }\n\n\n\n\n\n        void PPU_Render_CalculatePixel(bool borders)\n        {\n            // dots 1 through 256\n            if (PPU_Dot > 256)\n            {\n                borders = true;\n            }\n            if (PPU_Dot <= 256 || borders)\n            {\n                // there are 8 palettes in the PPU\n                // 4 are for the background, and the other 4 are for sprites.\n                byte Palette = 0;\n                // each of these palettes have 4 colors\n                byte Color = 0;\n                if (!borders)\n                {\n                    if (PPU_Mask_ShowBackground && (PPU_Dot > 8 || PPU_Mask_8PxShowBackground)) // if rendering is enables for this pixel\n                    {\n                        byte col0 = (byte)(((PPU_BackgroundPatternShiftRegisterL >> (15 - PPU_FineXScroll))) & 1); // take the bit from the shift register for the pattern low bit plane\n                        byte col1 = (byte)(((PPU_BackgroundPatternShiftRegisterH >> (15 - PPU_FineXScroll))) & 1); // take the bit from the shift register for the pattern high bit plane\n                        Color = (byte)((col1 << 1) | col0);\n\n                        byte pal0 = (byte)(((PPU_BackgroundAttributeShiftRegisterL) >> (7 - PPU_FineXScroll)) & 1); // take the bit from the shift register for the attribute low bit plane\n                        byte pal1 = (byte)(((PPU_BackgroundAttributeShiftRegisterH) >> (7 - PPU_FineXScroll)) & 1); // take the bit from the shift register for the attribute high bit plane\n                        Palette = (byte)((pal1 << 1) | pal0);\n\n                        if (Color == 0 && Palette != 0) // color 0 of all palettes are mirrors of color 0 of palette 0\n                        {\n                            Palette = 0;\n                        }\n                    }\n                }\n                // pretty much the same thing, but for sprites instead of background\n                byte SpritePalette = 0;\n                byte SpriteColor = 0;\n                bool SpritePriority = false; // if set, this sprite will be in front of background tiles. Otherwise, it will only take priority if the background is using color 0.\n                if (!borders)\n                {\n                    if (PPU_Mask_ShowSprites && (PPU_Dot > 8 || PPU_Mask_8PxShowSprites))\n                    {\n                        int i = 0;\n\n                        // check all 8 objects in secondary OAM\n                        while (i < 8)\n                        {\n                            if (PPU_SpriteShifterCounter[i] == 0 || SkippedPreRenderDot341) // if the shifter counter == 0 (the shifter counter is decremented each ppu cycle)\n                            {\n                                bool SpixelL = ((PPU_SpriteShiftRegisterL[i]) & 0x80) != 0; // take the bit from the shift register for the pattern low bit plane\n                                bool SpixelH = ((PPU_SpriteShiftRegisterH[i]) & 0x80) != 0; // take the bit from the shift register for the pattern high bit plane\n                                SpriteColor = 0;\n                                if (SpixelL) { SpriteColor = 1; }\n                                if (SpixelH) { SpriteColor |= 2; }\n\n                                SpritePalette = (byte)((PPU_SpriteAttribute[i] & 0x03) | 0x04); // read the palette from secondary OAM attributes.\n                                SpritePriority = ((PPU_SpriteAttribute[i] >> 5) & 1) == 0;      // read the priority from secondary OAM attributes.\n\n                            }\n                            else // if no objects are in range of this pixel...\n                            {\n                                i++; // try the next one\n                                continue;\n                            }\n\n                            if (SpriteColor != 0) // if we found an object, exit the loop. This means, objects earlier in secondary OAM hive higher priority over sprites later in secondary OAM\n                            {\n                                break;\n                            }\n\n                            i++; // This pixel wasn't a part of the previous object. Try the next slot in secondary oam.\n                        }\n\n                        // if we hit sprite zero and both rendering background and sprites are enabled...\n                        if (PPU_CanDetectSpriteZeroHit && i == 0 && PPU_CurrentScanlineContainsSpriteZero && PPU_Mask_ShowBackground && PPU_Mask_ShowSprites)\n                        {\n                            if (Color != 0 && SpriteColor != 0) // if both the background and sprites are visible on this pixel\n                            {\n                                if ((PPU_Mask_8PxShowSprites || PPU_Dot > 8) && PPU_Dot < 256) // and if this isn't on pixel 256, or in the first 8 pixels being masked away from the nametable, if that setting is enabled...\n                                {\n                                    PPUStatus_PendingSpriteZeroHit = true; // we did it! sprite zero hit achieved... the flag is set on teh next half-ppu-cycle.\n                                    PPU_CanDetectSpriteZeroHit = false; // another sprite zero hit cannot occur until the end of next vblank.\n                                    if (Logging) // and for some debug logging...\n                                    {\n                                        string S = DebugLog.ToString(); // let's add text to the current line letting me know a sprite zero hit occured, and on which dot\n                                        if (S.Length > 0)\n                                        {\n                                            S = S.Substring(0, S.Length - 2); // trim off \\n\n                                            DebugLog = new StringBuilder(S);\n                                            DebugLog.Append(\" ! Sprite Zero Hit ! (Dot \" + PPU_Dot + \")\\r\\n\");\n\n                                        }\n                                    }\n                                }\n                            }\n                        }\n\n                        // which do we draw, the background or the sprite?\n                        if (Color == 0 && SpriteColor != 0) // Well, if the background was using color 0, and the sprite wasn't,  always draw the sprite.\n                        {\n                            Color = SpriteColor; // I'm just reusing this background color variable.\n                            Palette = SpritePalette;       // I'm also just reusing the background palette variable.\n                        }\n                        else if (SpriteColor != 0) // the background color isn't zero...\n                        {\n                            if (SpritePriority) // if the sprite has priority, always draw the sprite.\n                            {\n                                Color = SpriteColor; // I'm just reusing this cackground color variable.\n                                Palette = SpritePalette; // I'm also just reusing the background palette variable.\n                            }\n                        }\n                    }\n                }\n                if ((PPU_Mask_ShowBackground || PPU_Mask_ShowSprites) && PPU_Scanline < 240) // if rendering is enabled...\n                {\n                    PaletteRAMAddress = (byte)(Palette << 2 | Color); // the Palette RAM address is determined by the palette and color we found.\n                }\n                else\n                {\n                    // rendering is disabled...\n                    if ((PPU_v & 0x3F1F) >= 0x3F00) // if v points to palette ram:\n                    {\n                        PaletteRAMAddress = (byte)(PPU_v & 0x1F); // The palette RAM address is simply wherever the v register is. (bitwise and with $1F due to palette RAM mirroring)\n                        if ((PaletteRAMAddress & 3) == 0)\n                        {\n                            PaletteRAMAddress &= 0x0F; // the transparent colors for sprites and backgrounds are shared.\n                        }\n                    }\n                    else\n                    {\n                        // EXT Pins\n                        PaletteRAMAddress = 0; // I'm not really emulating the EXT pins, and as far as I'm aware they aren't used in any games, official or homebrew.\n                        // This is typically why the background color is using Palette[0] when rendering is disabled.\n                    }\n                }\n\n                if (PPU_PaletteCorruptionRenderingDisabledOutOfVBlank || PPU_VRegisterChangedOutOfVBlank)\n                {\n                    PPU_VRegisterChangedOutOfVBlank = false;\n                    PPU_PaletteCorruptionRenderingDisabledOutOfVBlank = false;\n                    // PPU palette corruption!\n\n                    CorruptPalettes(Color, Palette);\n                    // This corruption also results in a single discolored pixel, and this occurs on all alignments.\n                    // I'm not entirely sure how this works, and I think it's the *next* pixel that gets corrupt? More research needed.\n\n                }\n\n                DotColor = (byte)((PaletteRAM[0x00 | PaletteRAMAddress]) & 0x3F); // Get the color by reading from Palette RAM\n\n                // though this is actually drawn to the screen 2 ppu cycles from now.\n            }\n        }\n\n        void CorruptPalettes(byte Color, byte Palette)\n        {\n            // Depending on the index into a color palette being used to select a color being drawn when rendering was disabled during a nametable fetch on a visible pixel with the PPU V Register (bitwise AND with $3FFF) being >= $3C00...\n            // Palettes get \"corrupted\" with a specific pattern.\n            // This pattern is determined by:\n            // The lowest nybble of the PPU's V register,\n            // The color index into the palette,\n            // and if this is using a sprite palette. (TODO: emulate this part)\n\n            // All of this was determined by observations with a custom test cart.\n            // It is entirely possible that the logic defined in this functions is incorrect, or possibly there are more factors at play.\n            // As far as I can tell though, this is \"good enough\" emulation of palette corruption.\n\n            if ((CPUClock & 3) != 2)\n            {\n                // this behavior occurs on other alignments, but seems consistent on alignment 2, and very hit or miss on other alignments.\n                // Currently, I'm only emulating this on alignment 2, but I'll probably change this in the future.\n                return;\n            }\n\n\n            byte[] CorruptedPalette = new byte[PaletteRAM.Length];\n            for (int i = 0; i < CorruptedPalette.Length; i++)\n            {\n                CorruptedPalette[i] = PaletteRAM[i];\n            }\n\n            switch (Color)\n            {\n                case 0:\n                    // simply take the low nybble from the V register. that's the color to corrupt.\n                    CorruptedPalette[PPU_v & 0xF] = (byte)((PaletteRAM[0] & PaletteRAM[PPU_v & 0xC]) | (PaletteRAM[0] & PaletteRAM[PPU_v & 0xF]) | (PaletteRAM[PPU_v & 0xC] & PaletteRAM[PPU_v & 0xF]));\n                    // TODO: Nybble 7 can corrupt color F. It's inconsistent though, so I'll need to circle back to this.\n\n                    break;\n                case 1:\n\n                    // To be honest, I'm not sure what's going on, so forgive the lack of comments.\n                    // There's almost a pattern, but again- unsure on why this is how it behaves.\n                    // and also it's likely this isn't entirely accurate, either due to mistyping something, or not enough research.\n\n                    switch (PPU_v & 0xF)\n                    {\n                        case 0:\n                            CorruptedPalette[0x0] = (byte)((PaletteRAM[0x1] & PaletteRAM[0xD]) | PaletteRAM[0x0]);\n                            CorruptedPalette[0x4] = PaletteRAM[0x5];\n                            CorruptedPalette[0x8] = PaletteRAM[0x9];\n                            CorruptedPalette[0xC] = PaletteRAM[0xD];\n                            break;\n                        case 1:\n                            break;\n                        case 2:\n                            CorruptedPalette[0x2] = (byte)((PaletteRAM[0x2] | PaletteRAM[0xD]) & PaletteRAM[0x3]);\n                            CorruptedPalette[0x3] = (byte)((PaletteRAM[0x1] | PaletteRAM[0x2]) & PaletteRAM[0x3]);\n                            CorruptedPalette[0x6] = (byte)((PaletteRAM[0x6] | PaletteRAM[0x5]) & PaletteRAM[0x7]);\n                            CorruptedPalette[0xA] = (byte)((PaletteRAM[0xA] | PaletteRAM[0x9]) & PaletteRAM[0xB]);\n                            CorruptedPalette[0xE] = PaletteRAM[0xD];\n                            CorruptedPalette[0xF] = PaletteRAM[0xD];\n                            break;\n                        case 3:\n                            CorruptedPalette[0x3] &= (byte)(PaletteRAM[0x1] | PaletteRAM[0xD]);\n                            CorruptedPalette[0xF] = PaletteRAM[0xD];\n                            break;\n                        case 4:\n                            CorruptedPalette[0x0] = PaletteRAM[0x1];\n                            CorruptedPalette[0x4] = (byte)((PaletteRAM[0x5] & PaletteRAM[0xD]) | PaletteRAM[0x4]);\n                            CorruptedPalette[0x8] = PaletteRAM[0x9];\n                            CorruptedPalette[0xC] = PaletteRAM[0xD];\n                            break;\n                        case 5:\n                            break;\n                        case 6:\n                            CorruptedPalette[0x2] = (byte)((PaletteRAM[0x2] | PaletteRAM[0x1]) & PaletteRAM[0x3]);\n                            CorruptedPalette[0x6] = (byte)((PaletteRAM[0x6] | PaletteRAM[0x7]) & PaletteRAM[0xD]);\n                            CorruptedPalette[0x7] = (byte)((PaletteRAM[0x7] | PaletteRAM[0x6]) & PaletteRAM[0x5]);\n                            CorruptedPalette[0xA] = (byte)((PaletteRAM[0xA] | PaletteRAM[0x9]) & PaletteRAM[0xB]);\n                            CorruptedPalette[0xE] = PaletteRAM[0xD];\n                            CorruptedPalette[0xF] = PaletteRAM[0xD];\n                            break;\n                        case 7:\n                            CorruptedPalette[0x7] &= (byte)(PaletteRAM[0x5] | PaletteRAM[0xD]);\n                            CorruptedPalette[0xF] = PaletteRAM[0xD];\n                            break;\n                        case 8:\n                            CorruptedPalette[0x0] = PaletteRAM[0x1];\n                            CorruptedPalette[0x4] = PaletteRAM[0x5];\n                            CorruptedPalette[0x8] = (byte)((PaletteRAM[0x9] & PaletteRAM[0xD]) | PaletteRAM[0x8]);\n                            CorruptedPalette[0xC] = PaletteRAM[0xD];\n                            break;\n                        case 9:\n                            break;\n                        case 0xA:\n                            CorruptedPalette[0x2] = (byte)((PaletteRAM[0x2] | PaletteRAM[0x1]) & PaletteRAM[0x3]);\n                            CorruptedPalette[0x6] = (byte)((PaletteRAM[0x6] | PaletteRAM[0xD]) & PaletteRAM[0x7]);\n                            CorruptedPalette[0xA] = (byte)((PaletteRAM[0xB] | PaletteRAM[0xD]) & PaletteRAM[0xA]);\n                            CorruptedPalette[0xB] = (byte)((PaletteRAM[0x9] | PaletteRAM[0xA]) & PaletteRAM[0xB]);\n                            CorruptedPalette[0xE] = PaletteRAM[0xD];\n                            CorruptedPalette[0xF] = PaletteRAM[0xD];\n                            break;\n                        case 0xB:\n                            CorruptedPalette[0xB] &= (byte)(PaletteRAM[0x9] | PaletteRAM[0xD]);\n                            CorruptedPalette[0xF] = PaletteRAM[0xD];\n                            break;\n                        case 0xC:\n                            CorruptedPalette[0x0] = PaletteRAM[0x1];\n                            CorruptedPalette[0x4] = PaletteRAM[0x5];\n                            CorruptedPalette[0x8] = PaletteRAM[0x9];\n                            CorruptedPalette[0xC] = PaletteRAM[0xD];\n                            break;\n                        case 0xD:\n                            break;\n                        case 0xE:\n                            CorruptedPalette[0x2] = (byte)((PaletteRAM[0x2] | PaletteRAM[0x1]) & PaletteRAM[0x3]);\n                            CorruptedPalette[0x6] = (byte)((PaletteRAM[0x6] | PaletteRAM[0xD]) & PaletteRAM[0x7]);\n                            CorruptedPalette[0xA] = (byte)((PaletteRAM[0xA] | PaletteRAM[0x9]) & PaletteRAM[0xB]);\n                            CorruptedPalette[0xE] = PaletteRAM[0xD];\n                            CorruptedPalette[0xF] = PaletteRAM[0xD];\n                            break;\n                        case 0xF:\n                            CorruptedPalette[0xF] = PaletteRAM[0xD];\n                            break;\n                    }\n\n\n                    // In some tests with case A, bit 3 ($08) of color 3 can remove bit 2 ($04) from the value of color 0 for the purposes of the bitwise AND. It's inconsistent though.\n\n\n                    break;\n                case 2:\n\n                    // To be honest, I'm not sure what's going on, so forgive the lack of comments.\n                    // There's almost a pattern, but again- unsure on why this is how it behaves.\n                    // and also it's likely this isn't entirely accurate, either due to mistyping something, or not enough research.\n\n                    switch (PPU_v & 0xF)\n                    {\n                        case 0:\n                            CorruptedPalette[0x0] = (byte)(PaletteRAM[0x0] | (PaletteRAM[0x2] & PaletteRAM[0xE]));\n                            CorruptedPalette[0x4] = PaletteRAM[0x6];\n                            CorruptedPalette[0x8] = PaletteRAM[0xA];\n                            CorruptedPalette[0xC] = PaletteRAM[0xE];\n                            break;\n                        case 1:\n                            CorruptedPalette[0x1] = (byte)((PaletteRAM[0x2] | PaletteRAM[0x1] | PaletteRAM[0xE]) & (PaletteRAM[0x3] | PaletteRAM[0xE]));\n                            CorruptedPalette[0x3] = (byte)((PaletteRAM[0x2] | PaletteRAM[0xE] | 0x3C) & PaletteRAM[0x3]);\n                            CorruptedPalette[0x5] = (byte)((PaletteRAM[0x6] | PaletteRAM[0x7]) & PaletteRAM[0x5]);\n                            CorruptedPalette[0x9] = (byte)((PaletteRAM[0xA] | PaletteRAM[0xB]) & PaletteRAM[0x9]);\n                            CorruptedPalette[0xD] = PaletteRAM[0xE];\n                            CorruptedPalette[0xF] = PaletteRAM[0xE];\n                            break;\n                        case 2:\n                            break;\n                        case 3:\n                            CorruptedPalette[0x3] &= (byte)(PaletteRAM[0x2] | PaletteRAM[0xE]);\n                            CorruptedPalette[0xF] = PaletteRAM[0xE];\n                            break;\n                        case 4:\n                            CorruptedPalette[0x0] = PaletteRAM[0x2];\n                            CorruptedPalette[0x4] = (byte)(PaletteRAM[0x4] | (PaletteRAM[0x6] & PaletteRAM[0xE]));\n                            CorruptedPalette[0x8] = PaletteRAM[0xA];\n                            CorruptedPalette[0xC] = PaletteRAM[0xE];\n                            break;\n                        case 5:\n                            CorruptedPalette[0x1] = (byte)((PaletteRAM[0x2] | PaletteRAM[0x1]) & PaletteRAM[0x3]);\n                            CorruptedPalette[0x5] = (byte)((PaletteRAM[0xE] | PaletteRAM[0x6]) & PaletteRAM[0x5]);\n                            CorruptedPalette[0x7] = (byte)((PaletteRAM[0xE] | PaletteRAM[0x6]) & PaletteRAM[0x7]);\n                            CorruptedPalette[0xD] = PaletteRAM[0xE];\n                            CorruptedPalette[0xF] = PaletteRAM[0xE];\n                            break;\n                        case 6:\n                            break;\n                        case 7:\n                            CorruptedPalette[0x7] &= (byte)(PaletteRAM[0x6] | PaletteRAM[0xE]);\n                            //CorruptedPalette[0xF] = PaletteRAM[0xE];\n                            break;\n                        case 8:\n                            CorruptedPalette[0x0] = PaletteRAM[0x2];\n                            CorruptedPalette[0x4] = PaletteRAM[0x6];\n                            CorruptedPalette[0x8] = (byte)(PaletteRAM[0x8] | (PaletteRAM[0xA] & PaletteRAM[0xE]));\n                            CorruptedPalette[0xC] = PaletteRAM[0xE];\n                            break;\n                        case 9:\n                            CorruptedPalette[0x1] = (byte)((PaletteRAM[0x2] | PaletteRAM[0x1]) & PaletteRAM[0x3]);\n                            CorruptedPalette[0x5] = (byte)((PaletteRAM[0x6] | PaletteRAM[0x5]) & PaletteRAM[0x7]);\n                            CorruptedPalette[0x9] = (byte)((PaletteRAM[0xE] | PaletteRAM[0xA] | 0x01) & PaletteRAM[0x9]);\n                            CorruptedPalette[0xB] = (byte)((PaletteRAM[0xE] | PaletteRAM[0xA] | 0x31) & PaletteRAM[0xB]);\n                            CorruptedPalette[0xD] = PaletteRAM[0xE];\n                            CorruptedPalette[0xF] = PaletteRAM[0xE];\n                            break;\n                        case 0xA:\n                            break;\n                        case 0xB:\n                            CorruptedPalette[0xB] &= (byte)(PaletteRAM[0xA] | PaletteRAM[0xE]);\n                            CorruptedPalette[0xF] = PaletteRAM[0xE];\n                            break;\n                        case 0xC:\n                            CorruptedPalette[0x0] = PaletteRAM[0x2];\n                            CorruptedPalette[0x4] = PaletteRAM[0x6];\n                            CorruptedPalette[0x8] = PaletteRAM[0xA];\n                            CorruptedPalette[0xC] = PaletteRAM[0xE];\n                            break;\n                        case 0xD:\n                            CorruptedPalette[0x1] = (byte)((PaletteRAM[0x2] | PaletteRAM[0x1]) & PaletteRAM[0x3]);\n                            CorruptedPalette[0x5] = (byte)((PaletteRAM[0x6] | PaletteRAM[0x5]) & PaletteRAM[0x7]);\n                            CorruptedPalette[0x9] = (byte)((PaletteRAM[0xA] | PaletteRAM[0x9]) & PaletteRAM[0xB]);\n                            CorruptedPalette[0xD] = PaletteRAM[0xE];\n                            CorruptedPalette[0xF] = PaletteRAM[0xE];\n                            break;\n                        case 0xE:\n                            break;\n                        case 0xF:\n                            CorruptedPalette[0xF] = PaletteRAM[0xE];\n                            break;\n                    }\n\n\n                    break;\n                case 3:\n\n                    // To be honest, I'm not sure what's going on, so forgive the lack of comments.\n                    // There's almost a pattern, but again- unsure on why this is how it behaves.\n                    // and also it's likely this isn't entirely accurate, either due to mistyping something, or not enough research.\n\n                    switch (PPU_v & 0xF)\n                    {\n                        case 0:\n                            CorruptedPalette[0x0] = (byte)((PaletteRAM[0x3] | (PaletteRAM[0xF] & PaletteRAM[0x0])));\n                            CorruptedPalette[0x4] &= PaletteRAM[0x7];\n                            CorruptedPalette[0x8] &= (byte)(PaletteRAM[0x9] | PaletteRAM[0xA] | PaletteRAM[0xB] | PaletteRAM[0xF] | 0x22); // magic number... Probably a temperature thing? I've seen 02, 22, 2C, or 2E\n                            CorruptedPalette[0xC] = PaletteRAM[0xF];\n                            break;\n                        case 1:\n                            CorruptedPalette[0x1] = (byte)((PaletteRAM[0x1] | PaletteRAM[0xF]) & PaletteRAM[0x3]);\n                            CorruptedPalette[0x5] = PaletteRAM[0x7];\n                            CorruptedPalette[0x9] = PaletteRAM[0xB];\n                            CorruptedPalette[0xD] = PaletteRAM[0xF];\n                            break;\n                        case 2:\n                            CorruptedPalette[0x2] = (byte)((PaletteRAM[0x3] | PaletteRAM[0xF]) & PaletteRAM[0x3]);\n                            CorruptedPalette[0x6] = PaletteRAM[0x7];\n                            CorruptedPalette[0xA] = PaletteRAM[0xB];\n                            CorruptedPalette[0xE] = PaletteRAM[0xF];\n                            break;\n                        case 3:\n                            break;\n                        case 4:\n                            CorruptedPalette[0x0] &= (byte)(((PaletteRAM[0xF] ^ 0xFF)) | PaletteRAM[0x1] | PaletteRAM[0x2] | PaletteRAM[0x3] | 0x7); // magic number... I've only seen it as 07 though.\n                            CorruptedPalette[0x4] &= (byte)(PaletteRAM[0x7] | PaletteRAM[0xF]);\n                            CorruptedPalette[0x8] &= (byte)(PaletteRAM[0xB] | PaletteRAM[0xF] | (PaletteRAM[0xC] ^ 0xFF));\n                            CorruptedPalette[0xC] = (byte)((PaletteRAM[0x7] & PaletteRAM[0xF]) | PaletteRAM[0xC]);\n                            break;\n                        case 5:\n                            CorruptedPalette[0x1] = PaletteRAM[0x3];\n                            CorruptedPalette[0x5] = (byte)((PaletteRAM[0x5] | PaletteRAM[0xF]) & PaletteRAM[0x7]);\n                            CorruptedPalette[0x9] = PaletteRAM[0xB];\n                            CorruptedPalette[0xD] = PaletteRAM[0xF];\n                            break;\n                        case 6:\n                            CorruptedPalette[0x2] = PaletteRAM[0x3];\n                            CorruptedPalette[0x6] = (byte)((PaletteRAM[0x6] | PaletteRAM[0xF]) & PaletteRAM[0x7]);\n                            CorruptedPalette[0xA] = PaletteRAM[0xB];\n                            CorruptedPalette[0xE] = PaletteRAM[0xF];\n                            break;\n                        case 7:\n                            break;\n                        case 8:\n                            CorruptedPalette[0x0] &= (byte)(((PaletteRAM[0xF] ^ 0xFF)) | PaletteRAM[0x1] | PaletteRAM[0x2] | PaletteRAM[0x3] | 0x23); // magic number... I've only seen it as 23 though.\n                            CorruptedPalette[0x4] = (byte)(PaletteRAM[0x7]);\n                            CorruptedPalette[0x8] &= (byte)(PaletteRAM[0xB] | PaletteRAM[0xF] | (PaletteRAM[0xC] ^ 0xFF));\n                            CorruptedPalette[0xC] = (byte)((PaletteRAM[0xB] & PaletteRAM[0xF]) | PaletteRAM[0xC]);\n                            break;\n                        case 9:\n                            CorruptedPalette[0x1] = PaletteRAM[0x3];\n                            CorruptedPalette[0x5] = PaletteRAM[0x7];\n                            CorruptedPalette[0x9] = (byte)((PaletteRAM[0x9] | PaletteRAM[0xF]) & PaletteRAM[0xB]);\n                            CorruptedPalette[0xD] = PaletteRAM[0xF];\n                            break;\n                        case 0xA:\n                            CorruptedPalette[0x2] = PaletteRAM[0x3];\n                            CorruptedPalette[0x6] = PaletteRAM[0x7];\n                            CorruptedPalette[0xA] = (byte)((PaletteRAM[0xA] | PaletteRAM[0xF]) & PaletteRAM[0xB]);\n                            CorruptedPalette[0xE] = PaletteRAM[0xF];\n                            break;\n                        case 0xB:\n                            break;\n                        case 0xC:\n                            CorruptedPalette[0x0] &= (byte)(((PaletteRAM[0xF] ^ 0xFF)) | PaletteRAM[0x1] | PaletteRAM[0x2] | PaletteRAM[0x3] | 0x37); // magic number... I've only seen it as 23 though.\n                            CorruptedPalette[0x4] = PaletteRAM[0x7];\n                            CorruptedPalette[0x8] &= (byte)(PaletteRAM[0xB] | 0x2F); // Magic number. I've seen 2F and 2E\n                            CorruptedPalette[0xC] = PaletteRAM[0xF];\n                            break;\n                        case 0xD:\n                            CorruptedPalette[0x1] = PaletteRAM[0x3];\n                            CorruptedPalette[0x5] = PaletteRAM[0x7];\n                            CorruptedPalette[0x9] = PaletteRAM[0xB];\n                            CorruptedPalette[0xD] = PaletteRAM[0xF];\n                            break;\n                        case 0xE:\n                            CorruptedPalette[0x2] = PaletteRAM[0x3];\n                            CorruptedPalette[0x6] = PaletteRAM[0x7];\n                            CorruptedPalette[0xA] = PaletteRAM[0xB];\n                            CorruptedPalette[0xE] = PaletteRAM[0xF];\n                            break;\n                        case 0xF:\n                            break;\n                    }\n\n                    break;\n\n\n            }\n            for (int i = 0; i < CorruptedPalette.Length; i++)\n            {\n                PaletteRAM[i] = CorruptedPalette[i];\n            }\n\n\n        }\n\n\n        byte PPU_RenderTemp; // a variable used in the following function to store information between ppu cycles.\n        bool PPU_Commit_NametableFetch;\n        bool PPU_Commit_AttributeFetch;\n        bool PPU_Commit_PatternLowFetch;\n        bool PPU_Commit_PatternHighFetch;\n\n        void PPU_Render_ShiftRegistersAndBitPlanes()\n        {\n            byte cycleTick; // for the switch statement below, this checks which case to run on a given ppu cycle.\n            cycleTick = (byte)((PPU_Dot+7) & 7);\n\n            if (PPU_ALE && PPU_READ)\n            {\n                Cart.Emu.PPU_OctalLatch = (byte)PPU_AddressBus;\n            }\n\n            switch (cycleTick)\n            {\n                case 0:\n                    PPU_PatternAddressRegister_NT = (ushort)(0x2000 + (PPU_v & 0x0FFF));\n                    PPU_PAR_MUX = PPU_PatternAddressRegister_NT;\n                    PPU_AddressBus = PPU_PAR_MUX;\n                    break;\n                case 1:\n                    // fetch byte from Nametable\n                    PPU_AddressBus = (ushort)((PPU_PatternAddressRegister_NT & 0xFF00) | PPU_OctalLatch);\n                    PPU_RenderTemp = Cart.MapperChip.FetchPPU();\n                    PPU_Commit_NametableFetch = true;\n                    break;\n                case 2:\n                    PPU_PatternAddressRegister_AT = (ushort)(0x23C0 | (PPU_v & 0x0C00) | ((PPU_v >> 4) & 0x38) | ((PPU_v >> 2) & 0x07));\n                    PPU_PAR_MUX = PPU_PatternAddressRegister_AT;\n                    PPU_AddressBus = PPU_PAR_MUX;\n                    break;\n                case 3:\n                    // fetch attribute byte from attribute table\n                    PPU_AddressBus = (ushort)((PPU_PatternAddressRegister_AT & 0xFF00) | PPU_OctalLatch);\n                    PPU_RenderTemp = Cart.MapperChip.FetchPPU();\n                    PPU_Commit_AttributeFetch = true;\n                    // now we only have the 2 bits we're looking for\n                    break;\n                case 4:\n                    PPU_CheckPAR();\n                    PPU_PatternAddressRegister_CHR &= 0b1111111110111;\n                    PPU_PAR_MUX = PPU_PatternAddressRegister_CHR;\n                    PPU_AddressBus = PPU_PAR_MUX;\n                    break;\n                case 5:\n                    // fetch pattern bits from value read off the nametable\n                    PPU_AddressBus = (ushort)((PPU_PatternAddressRegister_CHR & 0xFF00) | PPU_OctalLatch);\n                    PPU_RenderTemp = Cart.MapperChip.FetchPPU();\n                    PPU_Commit_PatternLowFetch = true;\n                    break;\n                case 6:\n                    PPU_CheckPAR();\n                    PPU_PatternAddressRegister_CHR |= 8;\n                    PPU_PAR_MUX = PPU_PatternAddressRegister_CHR;\n                    PPU_AddressBus = PPU_PAR_MUX;\n                    break;\n                case 7:\n                    // fetch pattern bits with the new address\n                    PPU_AddressBus = (ushort)((PPU_PatternAddressRegister_CHR & 0xFF00) | PPU_OctalLatch);\n                    PPU_RenderTemp = Cart.MapperChip.FetchPPU();\n                    PPU_Commit_PatternHighFetch = true;\n                    break;\n            }\n\n            if (PPU_ALE && !PPU_READ)\n            {\n                Cart.Emu.PPU_OctalLatch = (byte)PPU_AddressBus;\n            }\n\n        }\n\n        void PPU_Render_CommitShiftRegistersAndBitPlanes()\n        {\n            if (PPU_Commit_NametableFetch)\n            {\n                PPU_Commit_NametableFetch = false;\n                PPU_PatternAddressRegister_CHR &= 0b1000000001111;\n                if (PPU_Dot < 256 || PPU_Dot > 320)\n                {\n                    PPU_PatternAddressRegister_CHR |= (ushort)( (byte)(PPU_AddressBus) << 4);\n                }\n                else\n                {\n                    PPU_PatternAddressRegister_CHR |= (ushort)(OAM2[(OAM2Address&0x1C)+1]<< 4);\n                }\n            }\n            if (PPU_Commit_AttributeFetch)\n            {\n                PPU_Commit_AttributeFetch = false;\n                PPU_Attribute = PPU_RenderTemp;\n                // 1 byte of attribute data is 4 tiles worth. determine which tile this is for.\n                if ((PPU_v & 3) >= 2) // If this is on the right tile\n                {\n                    PPU_Attribute = (byte)(PPU_Attribute >> 2);\n                }\n                if ((((PPU_v & 0b0000001111100000) >> 5) & 3) >= 2) // If this is on the bottom tile\n                {\n                    PPU_Attribute = (byte)(PPU_Attribute >> 4);\n                }\n                PPU_Attribute = (byte)(PPU_Attribute & 3);\n            }\n            if (PPU_Commit_PatternLowFetch)\n            {\n                PPU_Commit_PatternLowFetch = false;\n                PPU_LowBitPlane = PPU_RenderTemp;\n            }\n            if (PPU_Commit_PatternHighFetch)\n            {\n                PPU_Commit_PatternHighFetch = false;\n                PPU_HighBitPlane = PPU_RenderTemp;\n                PPU_LoadShiftRegisters();\n                PPU_IncrementScrollX();\n            }\n        }\n\n        void PPU_Render_ShiftRegistersAndBitPlanes_DummyNT()\n        {\n\n            if (PPU_READ)\n            {\n                Cart.Emu.PPU_OctalLatch = (byte)PPU_AddressBus;\n            }\n\n            if (PPU_Dot == 0)\n            {\n                PPU_CheckPAR();\n                PPU_PatternAddressRegister_CHR &= 0b1111111110111;\n                PPU_AddressBus = PPU_PatternAddressRegister_CHR;\n            }\n            else\n            {\n                byte cycleTick; // for the switch statement below, this checks which case to run on a given ppu cycle.\n                cycleTick = (byte)(PPU_Dot - 337);\n\n                switch (cycleTick)\n                {\n                    case 0:\n                        PPU_AddressBus = (ushort)(0x2000 + (PPU_v & 0x0FFF));\n                        break;\n                    case 1:\n                        // fetch byte from Nametable\n                        PPU_AddressBus = (ushort)(0x2000 + (PPU_v & 0x0FFF));\n                        PPU_RenderTemp = Cart.MapperChip.FetchPPU();\n                        PPU_Commit_NametableFetch = true;\n                        break;\n                    case 2:\n                        PPU_AddressBus = (ushort)(0x2000 + (PPU_v & 0x0FFF));\n                        break;\n                    case 3:\n                        // fetch attribute byte from attribute table\n                        PPU_RenderTemp = Cart.MapperChip.FetchPPU();\n                        //IGNORED NT FETCH: This actually doesn't update the NT register.\n                        break;\n                }\n            }\n            if (PPU_ALE && !PPU_READ)\n            {\n                Cart.Emu.PPU_OctalLatch = (byte)PPU_AddressBus;\n            }\n        }\n\n        public void PPU_CheckPAR()\n        {\n            // Some bits in PAR change based on context:\n            if(PPU_Dot < 256 || PPU_Dot > 320)\n            {\n                // Which pattern table do we use for nametable fetches?\n                PPU_PatternAddressRegister_CHR &= 0b0111111111000;\n                PPU_PatternAddressRegister_CHR |= (ushort)(PPU_PatternSelect_Background ? 0b1000000000000 : 0);\n                PPU_PatternAddressRegister_CHR |= (ushort)((PPU_v & 0b0111000000000000) >> 12);\n            }\n            else\n            {\n                // Which pattern table do we use for sprite fetches?\n                if(!PPU_Spritex16)\n                {\n                    bool flipy = (OAM2[(OAM2Address & 0x1C) + 2] & 0x80) != 0;\n                    PPU_PatternAddressRegister_CHR &= 0b0111111111000;\n                    PPU_PatternAddressRegister_CHR |= (ushort)(PPU_PatternSelect_Sprites ? 0b1000000000000 : 0);\n                    PPU_PatternAddressRegister_CHR |= (ushort)(flipy ? 7-(InRangeCheck & 0x7) : (InRangeCheck & 0x7));\n                }\n                else\n                {\n                    bool flipy = (OAM2[(OAM2Address & 0x1C) + 2] & 0x80) != 0;\n                    PPU_PatternAddressRegister_CHR &= 0b0111111101000;\n                    PPU_PatternAddressRegister_CHR |= (ushort)(((OAM2[(OAM2Address&0x1C)+1] & 1) != 0) ? 0b1000000000000 : 0); // Bit 0 of the OAM2 Pattern\n                    PPU_PatternAddressRegister_CHR |= (ushort)(flipy ? 7 - (InRangeCheck & 0x7) : (InRangeCheck & 0x7));\n                    PPU_PatternAddressRegister_CHR |= (ushort)(((InRangeCheck & 0x08) ^ (flipy ? 8 : 0)) <<1);\n                }\n            }\n        }\n\n        // in sprite evaluation, if a sprite is horizontally mirrored, we need to flip all the order of the bits in the shift register.\n        public byte Flip(byte b)\n        {\n            b = (byte)(((b & 0xF0) >> 4) | ((b & 0xF) << 4));\n            b = (byte)(((b & 0xCC) >> 2) | ((b & 0x33) << 2));\n            b = (byte)(((b & 0xAA) >> 1) | ((b & 0x55) << 1));\n            return b;\n        }\n\n        void PPU_UpdateBackgroundShiftRegisters()\n        {\n            PPU_BackgroundPatternShiftRegisterL = (ushort)(PPU_BackgroundPatternShiftRegisterL << 1); // shift 1 bit to the left. Bring in a 0.\n            PPU_BackgroundPatternShiftRegisterH = (ushort)((PPU_BackgroundPatternShiftRegisterH << 1) | 1); // shift 1 bit to the left. Bring in a 1.\n            PPU_BackgroundAttributeShiftRegisterL = (ushort)((PPU_BackgroundAttributeShiftRegisterL << 1) | (PPU_AttributeLatchRegister & 1)); // shift 1 bit to the left. Bring in Attribute low bit.\n            PPU_BackgroundAttributeShiftRegisterH = (ushort)((PPU_BackgroundAttributeShiftRegisterH << 1) | ((PPU_AttributeLatchRegister & 10) >> 1)); // shift 1 bit to the left. Bring in Attribute high bit.\n        }\n\n        void UpdateSpriteShiftRegisters()\n        {\n            if (PPU_Dot <= 256) // the shift registers for sprites are shifted after the rendering process.\n            {\n                // shift all 8 sprite shift registers.\n                int i = 0;\n                while (i < 8)\n                {\n                    if (PPU_SpriteShifterCounter[i] > 0 && !SkippedPreRenderDot341)\n                    {\n                        PPU_SpriteShifterCounter[i]--; // decrement the X position of all objects in secondary OAM. When this is zero, the ppu can draw it.\n                    }\n                    else\n                    {\n                        if ((PPU_Mask_ShowSprites || PPU_Mask_ShowBackground)) // this happens if rendering either sprites or background.\n                        {\n                            PPU_SpriteShiftRegisterL[i] = (byte)(PPU_SpriteShiftRegisterL[i] << 1); // shift 1 bit to the left.\n                            PPU_SpriteShiftRegisterH[i] = (byte)(PPU_SpriteShiftRegisterH[i] << 1); // shift 1 bit to the left.\n                        }\n                    }\n                    i++;\n                }\n            }\n        }\n\n        void PPU_LoadShiftRegisters()\n        {\n            // this runs as the first step of PPU_Render_ShiftRegistersAndBitPlanes(), using the values determined by the previous 8 steps of PPU_Render_ShiftRegistersAndBitPlanes().\n            PPU_BackgroundPatternShiftRegisterL = (ushort)((PPU_BackgroundPatternShiftRegisterL & 0xFF00) | PPU_LowBitPlane);\n            PPU_BackgroundPatternShiftRegisterH = (ushort)((PPU_BackgroundPatternShiftRegisterH & 0xFF00) | PPU_HighBitPlane);\n            PPU_AttributeLatchRegister = PPU_Attribute;\n        }\n\n        void PPU_IncrementScrollX()\n        {\n            // used when setting up shift registers for the background\n            // update the v register. Either increment it, or reset the scroll\n            if ((PPU_v & 0x001F) == 31)\n            {\n                PPU_v &= 0xFFE0; // resetting the scroll\n                PPU_v ^= 0x0400;\n            }\n            else\n            {\n                PPU_v++; // increment\n            }\n        }\n\n        void PPU_IncrementScrollY()\n        {\n            if (CopyV)\n            {\n                PPU_v = (ushort)(PPU_Update2006Value_Temp & PPU_Update2006Value); // This isn't actually accurate. More research needed.\n            }\n            else\n            {\n                if ((PPU_v & 0x7000) != 0x7000)\n                {\n                    PPU_v += 0x1000;\n                }\n                else\n                {\n                    PPU_v &= 0x0FFF;\n                    int y = (PPU_v & 0x03E0) >> 5;\n                    if (y == 29)\n                    {\n                        y = 0; // reset the Y value and also flip some other bit in the 'v' register\n                        PPU_v ^= 0x0800;\n                    }\n                    else if (y == 31)\n                    {\n                        y = 0; // reset the Y value\n                    }\n                    else\n                    {\n                        y++; // increment the Y value\n                    }\n                    PPU_v = (ushort)((PPU_v & 0xFC1F) | (y << 5));\n                }\n            }\n        }\n\n        void PPU_ResetXScroll()\n        {\n            // If a write to $2000 occurs during this ppu cycle, PPU_TempVRAMAddress will be the incorrect value!\n            // The value of PPU_TempVRAMAddress will be corrected on the next ppu cycle, but it's already too late.\n            // This is the \"scanline bug\" : https://www.nesdev.org/wiki/PPU_glitches#PPUCTRL\n            // The bug is only visible if the nametable mirroring is vertical.\n            PPU_v = (ushort)((PPU_v & 0b0111101111100000) | (PPU_t & 0b0000010000011111));\n        }\n        void PPU_ResetYScroll()\n        {\n            // The exact same issue from PPU_ResetXScroll() can happen here too, except this corrupts an entire frame.\n            // The bug is only visible if the nametable mirroring is horizontal.\n            //PPU_TempVRAMAddress = (ushort)((PPU_TempVRAMAddress & 0b0111110000011111) | (0b000001111000000)); //Uncomment this line to experiment with the \"Attirbutes as tiles\" bug.\n            PPU_v = (ushort)((PPU_v & 0b0000010000011111) | (PPU_t & 0b0111101111100000));\n        }\n\n        void DecayPPUDataBus()\n        {\n            int i = 0;\n            while (i < PPUBusDecay.Length)\n            {\n                if (PPUBusDecay[i] > 0)\n                {\n                    PPUBusDecay[i]--;\n                    if (PPUBusDecay[i] == 0)\n                    {\n                        PPUBus &= DecayBitmask[i];\n                    }\n                }\n                i++;\n            }\n        }\n        byte[] DecayBitmask = { 0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F };\n\n        // The object attribute memory DMA!\n        bool OAMDMA_Aligned = false;\n        bool OAMDMA_Halt = false;\n        bool DMCDMA_Halt = false;\n        byte OAM_InternalBus;   // a data bus that's used for the OAM DMA\n        ushort OAMAddressBus;   // the address bus of the OAM DMA\n\n        // The DMAs (Direct Memory Accesses) Have \"get\" and \"put\" cycles.\n        // they can also be \"halted\" in which case, it will always read instead of write.\n\n        // the following functions,\n        // OAMDMA_Get()    : Get cycles are reads\n        // OAMDMA_Halted() : Halted gets and halted puts are both reads from the current address bus\n        // OAMDMA_Put()    : Put cycles are writes to OAM.\n\n        // DMCDMA_Get()    : Get cycles are reads\n        // DMCDMA_Halted() : Halted gets and halted puts are both reads from the current address bus\n        // DMCDMA_Put()    : Put cycles are writes to the DMC shifter.\n\n        void OAMDMA_Get()\n        {\n            OAMAddressBus = (ushort)(DMAPage << 8 | DMAAddress);\n            OAMDMA_Aligned = true;\n            // the fetch happens regardless of halt\n            OAM_InternalBus = Fetch(OAMAddressBus);\n        }\n        void OAMDMA_Halted()\n        {\n            Fetch(addressBus); // if halted, just read from the current address bus.\n        }\n\n        void OAMDMA_Put()\n        {\n\n            if (OAMDMA_Aligned) // if the DMA is aligned\n            {\n                Store(OAM_InternalBus, 0x2004); // write to OAM\n                DMAAddress++;\n                if (DMAAddress == 0) // if we overflow the DMA address\n                {\n                    DoOAMDMA = false; // we have completed the DMA.\n                    OAMDMA_Aligned = false;\n                    return;\n                }\n            }\n            else // if this is an alignment cycle\n            {\n                Fetch(addressBus); // just read from the current address bus\n            }\n\n        }\n\n        void DMCDMA_Get()\n        {\n            // now reload the DMC buffer.\n            APU_DMC_Buffer = Fetch(APU_DMC_AddressCounter);\n\n            APU_DMC_AddressCounter++;\n            if (APU_DMC_AddressCounter == 0)\n            {\n                APU_DMC_AddressCounter = 0x8000;\n            }\n            if (APU_DMC_BytesRemaining > 0)\n            {\n                // due to writes to $4015 setting the BytesRemaining to 0 if disabled, this could potentially underflow without the if statement.\n                APU_DMC_BytesRemaining--;\n            }\n\n            if (APU_DMC_BytesRemaining == 0)\n            {\n                //reset sample\n\n                if (!APU_DMC_Loop)\n                {\n                    APU_Status_DMC = false;\n                    if (APU_DMC_EnableIRQ) // if the DMC should fire an IRQ when it completes...\n                    {\n                        IRQ_LevelDetector = true;\n                        APU_Status_DMCInterrupt = true;\n                    }\n                }\n                else\n                {\n                    StartDMCSample();\n                }\n            }\n            DoDMCDMA = false;\n            OAMDMA_Aligned = false;\n            CannotRunDMCDMARightNow = 2;\n\n        }\n\n        void DMCDMA_Halted()\n        {\n            Fetch(addressBus);\n        }\n        void DMCDMA_Put()\n        {\n            Fetch(addressBus);\n        }\n\n        // Typically in the last CPU cycle of an instruction, the console will check if the NMI edge detector or IRQ level detector is set. In which case, it's time to run an interrupt.\n        // The timing on this is different for branch instructions, and the BRK instruction doesn't do this at all.\n        void PollInterrupts()\n        {\n            NMI_PreviousPinsSignal = NMI_PinsSignal;\n            NMI_PinsSignal = NMILine;\n            if (NMI_PinsSignal && !NMI_PreviousPinsSignal)\n            {\n                DoNMI = true;\n            }\n            DoIRQ = IRQLine && !flag_Interrupt;\n        }\n\n        void PollInterrupts_CantDisableIRQ()\n        {\n            NMI_PreviousPinsSignal = NMI_PinsSignal;\n            NMI_PinsSignal = NMILine;\n            if (NMI_PinsSignal && !NMI_PreviousPinsSignal)\n            {\n                DoNMI = true;\n            }\n            if (!DoIRQ)\n            {\n                DoIRQ = IRQLine && !flag_Interrupt;\n            }\n        }\n\n        void CompleteOperation()\n        {\n            operationCycle = 0xFF; // this will be incremented to 0.\n            addressBus = programCounter;\n            CPU_Read = true;\n            IgnoreH = false;\n        }\n\n        public void _6502()\n        {\n            if ((DoDMCDMA && (APU_Status_DMC || APU_ImplicitAbortDMC4015) && CPU_Read) || (DoOAMDMA && CPU_Read)) // Are we running a DMA? Did it fail? Also some specific behavior can force a DMA to abort. Did that occur?\n            {\n                if (\n                    (opCode == 0x93 && operationCycle == 4) ||\n                    (opCode == 0x9B && operationCycle == 3) ||\n                    (opCode == 0x9C && operationCycle == 3) ||\n                    (opCode == 0x9E && operationCycle == 3) ||\n                    (opCode == 0x9F && operationCycle == 3)\n                    )\n                {\n                    IgnoreH = true;\n                }\n\n                if (DoOAMDMA && FirstCycleOfOAMDMA)\n                {\n                    FirstCycleOfOAMDMA = false;\n                    if (!APU_PutCycle) // if the first cycle of an OAM DMA is a get cycle, it's a halt cycle.\n                    {\n                        OAMDMA_Halt = true;\n                    }\n                }\n\n                if (APU_PutCycle)\n                {\n                    // Put cycle (write)\n                    if (DoDMCDMA && DoOAMDMA) // if we're running both a DMC and OAM DMA.\n                    {\n                        if (DMCDMA_Halt && OAMDMA_Halt) // both halt cycles\n                        {\n                            OAMDMA_Halted();\n                        }\n                        else if (!OAMDMA_Halt && DMCDMA_Halt) // only DMC halted\n                        {\n                            OAMDMA_Put();\n                        }\n                        else if (OAMDMA_Halt && !DMCDMA_Halt) // only OAM halted\n                        {\n                            DMCDMA_Put(); // Can this logically ever happen?\n                        }\n                        else // none halted : OAM DMA has priority\n                        {\n                            OAMDMA_Put();\n                        }\n                    }\n                    else // only performing a single DMA\n                    {\n                        if (DoDMCDMA) // only running DMC DMA\n                        {\n                            if (DMCDMA_Halt)\n                            {\n                                DMCDMA_Halted();\n                            }\n                            else\n                            {\n                                DMCDMA_Put();\n                            }\n                        }\n                        else // only running OAM DMA\n                        {\n                            if (OAMDMA_Halt)\n                            {\n                                OAMDMA_Halted();\n                            }\n                            else\n                            {\n                                OAMDMA_Put();\n                            }\n                        }\n                    }\n                }\n                else\n                {\n                    // Get cycle (read)\n                    if (DoDMCDMA && DoOAMDMA) // if we're running both a DMC and OAM DMA.\n                    {\n                        if (DMCDMA_Halt && OAMDMA_Halt) // both halt cycles\n                        {\n                            DMCDMA_Halted();\n                        }\n                        else if (!OAMDMA_Halt && DMCDMA_Halt) // only DMC halted\n                        {\n                            OAMDMA_Get();\n                        }\n                        else if (OAMDMA_Halt && !DMCDMA_Halt) // only OAM halted\n                        {\n                            DMCDMA_Get();\n                        }\n                        else // none halted : DMC DMA has priority\n                        {\n                            DMCDMA_Get();\n                        }\n                    }\n                    else\n                    {\n                        // only performing a single DMA\n                        if (DoDMCDMA) // only running DMC DMA\n                        {\n                            if (DMCDMA_Halt)\n                            {\n                                DMCDMA_Halted();\n                            }\n                            else\n                            {\n                                DMCDMA_Get();\n                            }\n                        }\n                        else // only running OAM DMA\n                        {\n                            if (OAMDMA_Halt)\n                            {\n                                OAMDMA_Halted();\n                            }\n                            else\n                            {\n                                OAMDMA_Get();\n                            }\n                        }\n                    }\n\n                    DMCDMA_Halt = false; // both halt cycles get cleared after a get cycle.\n                    OAMDMA_Halt = false;\n                }\n\n            }\n            else if (operationCycle == 0) // We are not running any DMAs, and this is the first cycle of an instruction.\n            {\n\n                // cycle 0. fetch opcode:\n                addressBus = programCounter;\n\n                opCode = Fetch(addressBus); // Fetch the value at the program counter. This is the opcode.\n\n\n                if (DoNMI) // If an NMI is occurring,\n                {\n                    opCode = 0; // replace the opcode with 0. (A BRK, which has modified behavior for NMIs)\n                }\n                else if (DoIRQ) // If an IRQ is occurring,\n                {\n                    opCode = 0; // replace the opcode with 0. (A BRK, which has modified behavior for IRQs)\n                }\n                else if (DoReset) // If a RESET is occurring,\n                {\n                    opCode = 0; // replace the opcode with 0. (A BRK, which has modified behavior for RESETs)\n                }\n                else if (opCode == 0) // Otherwise, if an interrupt is not occurring, and the opcode is already 0\n                {\n                    DoBRK = true; // There's also specific behavior for the BRK instruction if it is in-fact a BRK, and not an interrupt.\n                }\n\n\n                if (Logging && !LoggingPPU) // For debugging only.\n                {\n                    Debug(); // This is where the tracelogger occurs.\n                }\n                if ((!DoNMI && !DoIRQ && !DoReset)) // If we aren't running any interrupts...\n                {\n                    programCounter++; // the PC is incremented to the next address\n                    addressBus = programCounter;\n                }\n\n                operationCycle++; // increment this for use in the following CPU cycle.\n\n            }\n            else\n            {\n                // a really big switch statement.\n                // depending on the value of the opcode, different behavior will take place.\n                // this is how instructions work.\n\n                // All instructions are labeled. If it's an undocumented opcode, I also write \"***\" next to it.\n\n                switch (opCode)\n                {\n                    case 0x00: //BRK\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                if (!DoBRK)\n                                {\n                                    Fetch(addressBus); //dummy fetch without incrementing PC.\n                                }\n                                else\n                                {\n                                    GetImmediate(); //dummy fetch and PC increment\n                                }\n                                break;\n                            case 2:\n                                if (!DoReset)\n                                {\n                                    Push((byte)(programCounter >> 8));\n                                }\n                                else\n                                {\n                                    ResetReadPush();\n                                }\n                                break;\n                            case 3:\n                                if (!DoReset)\n                                {\n                                    Push((byte)programCounter);\n                                }\n                                else\n                                {\n                                    ResetReadPush();\n                                }\n                                break;\n                            case 4:\n                                if (!DoReset)\n                                {\n                                    status = flag_Carry ? (byte)0x01 : (byte)0;\n                                    status |= flag_Zero ? (byte)0x02 : (byte)0;\n                                    status |= flag_Interrupt ? (byte)0x04 : (byte)0;\n                                    status |= flag_Decimal ? (byte)0x08 : (byte)0;\n                                    status |= DoBRK ? (byte)0x10 : (byte)0;\n                                    status |= 0x20;\n                                    status |= flag_Overflow ? (byte)0x40 : (byte)0;\n                                    status |= flag_Negative ? (byte)0x80 : (byte)0;\n                                    Push(status);\n                                }\n                                else\n                                {\n                                    ResetReadPush();\n                                }\n                                PollInterrupts(); // check for NMI?\n                                break;\n                            case 5:\n                                if (DoNMI)\n                                {\n                                    programCounter = (ushort)((programCounter & 0xFF00) | (Fetch(0xFFFA)));\n                                }\n                                else if (DoReset)\n                                {\n                                    programCounter = (ushort)((programCounter & 0xFF00) | (Fetch(0xFFFC)));\n                                }\n                                else\n                                {\n                                    programCounter = (ushort)((programCounter & 0xFF00) | (Fetch(0xFFFE)));\n                                }\n\n                                break;\n                            case 6:\n                                if (DoNMI)\n                                {\n                                    programCounter = (ushort)((programCounter & 0xFF) | (Fetch(0xFFFB) << 8));\n                                }\n                                else if (DoReset)\n                                {\n                                    programCounter = (ushort)((programCounter & 0xFF) | (Fetch(0xFFFD) << 8));\n                                }\n                                else\n                                {\n                                    programCounter = (ushort)((programCounter & 0xFF) | (Fetch(0xFFFF) << 8));\n                                }\n\n                                CompleteOperation(); // notably, BRK does not check the NMI edge detector at the end of the instruction\n                                DoReset = false;\n\n                                DoNMI = false;\n                                DoIRQ = false;\n                                IRQLine = false;\n\n                                DoBRK = false;\n\n                                flag_Interrupt = true;\n\n\n\n                                break;\n                        }\n                        break;\n\n                    case 0x01: //(ORA, X)\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffX();\n                                break;\n                            case 5: // read from address\n                                PollInterrupts();\n                                Op_ORA(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x02: ///HLT ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                dl = Fetch(addressBus);\n                                break;\n                            case 2:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 3:\n                            case 4:\n                                addressBus = 0xFFFE;\n                                Fetch(addressBus);\n                                break;\n                            case 5:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 6:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                operationCycle = 5; //makes this loop infinitely.\n                                break;\n                        }\n                        break;\n\n                    case 0x03: //(SLO, X)  *** \n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffX();\n                                break;\n                            case 5: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 6: // write back to the address\n                                Store(dl, addressBus);\n                                break; // perform the operation\n                            case 7:\n                                PollInterrupts();\n                                Op_SLO(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x04: //DOP ***\n                        if (operationCycle == 1)\n                        {\n                            GetAddressZeroPage();\n                        }\n                        else\n                        {\n                            // read from address\n                            PollInterrupts();\n                            Fetch(addressBus);\n                            CompleteOperation();\n                        }\n                        break;\n\n                    case 0x05: //ORA zp\n                        if (operationCycle == 1)\n                        {\n                            GetAddressZeroPage();\n                        }\n                        else\n                        {\n                            // read from address\n                            PollInterrupts();\n                            Op_ORA(Fetch(addressBus));\n                            CompleteOperation();\n                        }\n                        break;\n\n                    case 0x06: //ASL, zp\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 3: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 4: // perform operation\n                                PollInterrupts();\n                                Op_ASL(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x07: //SLO zp  *** \n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 3: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 4: // perform operation\n                                PollInterrupts();\n                                Op_SLO(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x08: //PHP\n\n                        if (operationCycle == 1)\n                        {\n                            //dummy fetch\n                            Fetch(addressBus);\n                        }\n                        else\n                        {\n                            PollInterrupts();\n                            // read from address\n                            status = flag_Carry ? (byte)0x01 : (byte)0;\n                            status += flag_Zero ? (byte)0x02 : (byte)0;\n                            status += flag_Interrupt ? (byte)0x04 : (byte)0;\n                            status += flag_Decimal ? (byte)0x08 : (byte)0;\n                            status += 0x10; //always set in PHP\n                            status += 0x20; //always set in PHP\n                            status += flag_Overflow ? (byte)0x40 : (byte)0;\n                            status += flag_Negative ? (byte)0x80 : (byte)0;\n                            Push(status);\n                            CompleteOperation();\n                        }\n                        break;\n\n                    case 0x09: //ORA Imm\n                        PollInterrupts();\n                        GetImmediate();\n                        Op_ORA(dl);\n                        CompleteOperation();\n                        break;\n\n                    case 0x0A: //ASL A\n                        PollInterrupts();\n                        Fetch(addressBus); // dummy read\n                        Op_ASL_A();\n                        CompleteOperation();\n                        break;\n\n                    case 0x0B: //ANC Imm ***\n                        PollInterrupts();\n                        GetImmediate();\n                        A = (byte)(A & dl);\n                        flag_Carry = A >= 0x80;\n                        flag_Zero = A == 0;\n                        flag_Negative = A >= 0x80;\n                        CompleteOperation();\n\n                        break;\n\n                    case 0x0C: //TOP ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Fetch(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x0D: //ORA Abs\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Op_ORA(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x0E: //ASL, Abs\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Op_ASL(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x0F: //SLO Abs  *** \n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Op_SLO(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x10: //BPL\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                PollInterrupts();\n                                GetImmediate();\n                                if (flag_Negative)\n                                {\n                                    CompleteOperation();\n                                }\n                                break;\n                            case 2:\n                                Fetch(addressBus); // dummy read\n                                temporaryAddress = (ushort)(programCounter + ((dl >= 0x80) ? -(256 - dl) : dl));\n                                programCounter = (ushort)((programCounter & 0xFF00) | (byte)((programCounter & 0xFF) + dl));\n                                addressBus = programCounter;\n                                if ((temporaryAddress & 0xFF00) == (programCounter & 0xFF00))\n                                {\n                                    CompleteOperation();\n                                }\n                                break;\n                            case 3: // read from address\n                                PollInterrupts_CantDisableIRQ(); // If the first poll detected an IRQ, this second poll should not be allowed to un-set the IRQ.\n                                Fetch(addressBus); // dummy read\n                                programCounter = (ushort)((programCounter & 0xFF) | (temporaryAddress & 0xFF00));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x11: //(ORA) Y\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffY(true);\n                                break;\n                            case 5: // read from address\n                                PollInterrupts();\n                                Op_ORA(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x12: ///HLT ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                dl = Fetch(addressBus);\n                                break;\n                            case 2:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 3:\n                            case 4:\n                                addressBus = 0xFFFE;\n                                Fetch(addressBus);\n                                break;\n                            case 5:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 6:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                operationCycle = 5; //makes this loop infinitely.\n                                break;\n                        }\n                        break;\n\n                    case 0x13: //(SLO) Y  *** \n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffY(false);\n                                break;\n                            case 5: // dummy read\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 6: // dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 7: // read from address\n                                PollInterrupts();\n                                Op_SLO(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x14: //DOP ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Fetch(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x15: //ORA zp, X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Op_ORA(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x16: //ASL, zp X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Op_ASL(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x17: //SLO zp X *** \n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Op_SLO(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x18: //CLC\n                        PollInterrupts();\n                        Fetch(addressBus); // dummy read\n                        flag_Carry = false;\n                        CompleteOperation();\n                        break;\n\n                    case 0x19: //ORA Abs, Y\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffY(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Op_ORA(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x1A: //NOP ***\n                        PollInterrupts();\n                        Fetch(addressBus);\n                        CompleteOperation();\n                        break;\n\n                    case 0x1B: //SLO Abs Y *** \n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressAbsOffY(false);\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5:// dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 6:// read from address\n                                PollInterrupts();\n                                Op_SLO(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x1C: //TOP ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffX(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Fetch(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x1D: //ORA Abs, X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffX(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Op_ORA(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x1E: //ASL, Abs, X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressAbsOffX(false);\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5:// dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 6:// read from address\n                                PollInterrupts();\n                                Op_ASL(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n\n                    case 0x1F: //SLO Abs, X *** \n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressAbsOffX(false);\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5:// dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 6:// read from address\n                                PollInterrupts();\n                                Op_SLO(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x20: //JSR\n\n                        switch (operationCycle)\n                        {\n                            // this is pretty cursed, though according to visual6502, this is apparently what happens.\n                            case 1: // fetch the byte that will be PC low\n                                addressBus = programCounter;\n                                dl = Fetch(addressBus);\n                                programCounter++;\n                                break;\n                            case 2: // transfer stack pointer to address bus, and alu to stack pointer. I'm just reusing `dl` here, but this instruction actually uses the Arithmetic Logic Unit for this.\n                                addressBus = (ushort)(0x100 | stackPointer);\n                                stackPointer = dl;\n                                CPU_Read = false;\n                                Fetch(addressBus); // dummy read\n                                break;\n                            case 3: // push PC high to stack via address bus\n                                Store((byte)((programCounter & 0xFF00) >> 8), addressBus);\n                                addressBus = (ushort)((byte)(addressBus - 1) | 0x100);\n                                break;\n                            case 4: // push PC low to stack via address bus\n                                Store((byte)(programCounter & 0xFF), addressBus);\n                                addressBus = (ushort)((byte)(addressBus - 1) | 0x100);\n                                specialBus = (byte)addressBus;\n                                CPU_Read = true;\n                                break;\n                            case 5: // fetch PC High, transfer stack pointer to PC low, address bus to stack pointer.\n                                PollInterrupts();\n                                addressBus = programCounter;\n                                programCounter = (ushort)((Fetch(addressBus) << 8) | stackPointer);\n                                stackPointer = specialBus;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x21: //(AND, X)\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffX();\n                                break;\n                            case 5: // read from address\n                                PollInterrupts();\n                                Op_AND(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x22: ///HLT ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                dl = Fetch(addressBus);\n                                break;\n                            case 2:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 3:\n                            case 4:\n                                addressBus = 0xFFFE;\n                                Fetch(addressBus);\n                                break;\n                            case 5:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 6:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                operationCycle = 5; //makes this loop infinitely.\n                                break;\n                        }\n                        break;\n\n                    case 0x23: //(RLA, X)  ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffX();\n                                break;\n                            case 5: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 6: // write back to the address\n                                Store(dl, addressBus);\n                                break; // perform the operation\n                            case 7:\n                                PollInterrupts();\n                                Op_RLA(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x24: //BIT Zp\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                PollInterrupts();\n                                dl = Fetch(addressBus);\n                                flag_Zero = (A & dl) == 0;\n                                flag_Negative = (dl & 0x80) != 0;\n                                flag_Overflow = (dl & 0x40) != 0;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x25: //AND zp\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                PollInterrupts();\n                                Op_AND(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x26: //ROL zp\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 3: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 4: // perform operation\n                                PollInterrupts();\n                                Op_ROL(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x27: //RLA zp  ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 3: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 4: // perform operation\n                                PollInterrupts();\n                                Op_RLA(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x28: //PLP\n                        switch (operationCycle)\n                        {\n                            case 1: //dummy fetch\n                                Fetch(addressBus);\n                                break;\n                            case 2: //increment S\n                                addressBus = (ushort)(0x100 + stackPointer);\n                                Fetch(addressBus); // dummy read\n                                stackPointer++;\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                addressBus = (ushort)(0x100 + stackPointer);\n                                status = Fetch(addressBus);\n                                flag_Carry = (status & 1) == 1;\n                                flag_Zero = ((status & 0x02) >> 1) == 1;\n                                flag_Interrupt = ((status & 0x04) >> 2) == 1;\n                                flag_Decimal = ((status & 0x08) >> 3) == 1;\n                                flag_Overflow = ((status & 0x40) >> 6) == 1;\n                                flag_Negative = ((status & 0x80) >> 7) == 1;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x29: //AND Imm\n                        PollInterrupts();\n                        GetImmediate();\n                        Op_AND(dl);\n                        CompleteOperation();\n                        break;\n\n                    case 0x2A: //ROL A\n                        PollInterrupts();\n                        Fetch(addressBus); // dummy read\n                        Op_ROL_A();\n                        CompleteOperation();\n                        break;\n\n                    case 0x2B: //ANC Imm *** (same as 0x0B)\n                        PollInterrupts();\n                        GetImmediate();\n                        A = (byte)(A & dl);\n                        flag_Carry = A >= 0x80;\n                        flag_Zero = A == 0;\n                        flag_Negative = A >= 0x80;\n                        CompleteOperation();\n\n                        break;\n\n                    case 0x2C: //BIT Abs\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                dl = Fetch(addressBus);\n                                flag_Zero = (A & dl) == 0;\n                                flag_Negative = (dl & 0x80) != 0;\n                                flag_Overflow = (dl & 0x40) != 0;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x2D: //AND Abs\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Op_AND(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x2E: //ROL Abs\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Op_ROL(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x2F: //RLA Abs ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Op_RLA(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x30: //BMI\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                PollInterrupts();\n                                GetImmediate();\n                                if (!flag_Negative)\n                                {\n                                    CompleteOperation();\n                                }\n                                break;\n                            case 2:\n                                Fetch(addressBus); // dummy read\n                                temporaryAddress = (ushort)(programCounter + ((dl >= 0x80) ? -(256 - dl) : dl));\n                                programCounter = (ushort)((programCounter & 0xFF00) | (byte)((programCounter & 0xFF) + dl));\n                                addressBus = programCounter;\n                                if ((temporaryAddress & 0xFF00) == (programCounter & 0xFF00))\n                                {\n                                    CompleteOperation();\n                                }\n                                break;\n                            case 3: // read from address\n                                PollInterrupts_CantDisableIRQ(); // If the first poll detected an IRQ, this second poll should not be allowed to un-set the IRQ.\n                                Fetch(addressBus); // dummy read\n                                programCounter = (ushort)((programCounter & 0xFF) | (temporaryAddress & 0xFF00));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x31: //(AND), Y\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffY(true);\n                                break;\n                            case 5: // read from address\n                                PollInterrupts();\n                                Op_AND(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x32: ///HLT ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                dl = Fetch(addressBus);\n                                break;\n                            case 2:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 3:\n                            case 4:\n                                addressBus = 0xFFFE;\n                                Fetch(addressBus);\n                                break;\n                            case 5:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 6:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                operationCycle = 5; //makes this loop infinitely.\n                                break;\n                        }\n                        break;\n                    case 0x33: //(RLA), Y  ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffY(false);\n                                break;\n                            case 5: // dummy read\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 6: // dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 7: // read from address\n                                PollInterrupts();\n                                Op_RLA(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x34: //DOP ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Fetch(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x35: //AND zp, X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Op_AND(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x36: //ROL zp, X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Op_ROL(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x37: //RLA zp, X  ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Op_RLA(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x38: //SEC\n                        PollInterrupts();\n                        Fetch(addressBus); // dummy read\n                        flag_Carry = true;\n                        CompleteOperation();\n                        break;\n\n                    case 0x39: //AND Abs, Y\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffY(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Op_AND(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x3A: //NOP ***\n                        PollInterrupts();\n                        addressBus = programCounter; Fetch(addressBus);\n                        CompleteOperation();\n                        break;\n\n                    case 0x3B: //RLA Abs, Y ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressAbsOffY(false);\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5:// dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 6:// read from address\n                                PollInterrupts();\n                                Op_RLA(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x3C: //TOP ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffX(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Fetch(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x3D: //AND Abs, X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffX(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Op_AND(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x3E: //ROL Abs, X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressAbsOffX(false);\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5:// dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 6:// read from address\n                                PollInterrupts();\n                                Op_ROL(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x3F: //RLA Abs, X ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressAbsOffX(false);\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5:// dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 6:// read from address\n                                PollInterrupts();\n                                Op_RLA(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x40: //RTI\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetImmediate();\n                                break;\n                            case 2:\n                                addressBus = (ushort)(0x100 | stackPointer);\n                                Fetch(addressBus);\n                                addressBus = (ushort)((byte)(addressBus + 1) | 0x100);\n                                break;\n                            case 3:\n                                status = Fetch(addressBus);\n                                flag_Carry = (status & 1) != 0;\n                                flag_Zero = (status & 0x02) != 0;\n                                flag_Interrupt = (status & 0x04) != 0;\n                                flag_Decimal = (status & 0x08) != 0;\n                                flag_Overflow = (status & 0x40) != 0;\n                                flag_Negative = (status & 0x80) != 0;\n\n                                addressBus = (ushort)((byte)(addressBus + 1) | 0x100);\n                                break;\n                            case 4:\n                                dl = Fetch(addressBus);\n                                programCounter = (ushort)((programCounter & 0xFF00) | dl); //technically not accurate, as this happens in cycle 5\n                                addressBus = (ushort)((byte)(addressBus + 1) | 0x100);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                dl = Fetch(addressBus);\n                                programCounter = (ushort)((programCounter & 0xFF) | (dl << 8));\n                                stackPointer = (byte)addressBus;\n                                CompleteOperation();\n                                break;\n\n                        }\n                        break;\n\n                    case 0x41: //(EOR X)\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffX();\n                                break;\n                            case 5: // read from address\n                                PollInterrupts();\n                                Op_EOR(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x42: ///HLT ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                dl = Fetch(addressBus);\n                                break;\n                            case 2:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 3:\n                            case 4:\n                                addressBus = 0xFFFE;\n                                Fetch(addressBus);\n                                break;\n                            case 5:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 6:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                operationCycle = 5; //makes this loop infinitely.\n                                break;\n                        }\n                        break;\n\n                    case 0x43: //(SRE, X) ***\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffX();\n                                break;\n                            case 5: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 6: // write back to the address\n                                Store(dl, addressBus);\n                                break; // perform the operation\n                            case 7:\n                                PollInterrupts();\n                                Op_SRE(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x44: //DOP ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                PollInterrupts();\n                                Fetch(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x45: //EOR zp\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                PollInterrupts();\n                                Op_EOR(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x46: //LSR zp\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 3: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 4: // perform operation\n                                PollInterrupts();\n                                Op_LSR(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x47: //SRE zp ***\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 3: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 4: // perform operation\n                                PollInterrupts();\n                                Op_SRE(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x48: //PHA\n\n                        switch (operationCycle)\n                        {\n                            case 1: //dummy fetch\n                                dl = Fetch(addressBus);\n                                break;\n                            case 2: // read from address\n                                PollInterrupts();\n                                Push(A);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x49: //EOR Imm\n                        PollInterrupts();\n                        GetImmediate();\n                        Op_EOR(dl);\n                        CompleteOperation();\n                        break;\n\n                    case 0x4A: //LSR A\n                        PollInterrupts();\n                        Fetch(addressBus); // dummy read\n                        Op_LSR_A();\n                        CompleteOperation();\n                        break;\n\n                    case 0x4B: //ASR Imm ***\n                        PollInterrupts();\n                        GetImmediate();\n                        A = (byte)(A & dl);\n                        Op_LSR_A();\n                        CompleteOperation();\n                        break;\n\n                    case 0x4C: //JMP\n                        if (operationCycle == 1)\n                        {\n                            GetAddressAbsolute();\n\n                        }\n                        else\n                        {\n                            PollInterrupts();\n                            GetAddressAbsolute();\n                            programCounter = addressBus;\n                            CompleteOperation();\n                        }\n                        break;\n\n                    case 0x4D: //EOR Abs\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Op_EOR(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x4E: //LSR abs\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Op_LSR(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x4F: //SRE abs ***\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Op_SRE(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x50: //BVC\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                PollInterrupts();\n                                GetImmediate();\n                                if (flag_Overflow)\n                                {\n                                    CompleteOperation();\n                                }\n                                break;\n                            case 2:\n                                Fetch(addressBus); // dummy read\n                                temporaryAddress = (ushort)(programCounter + ((dl >= 0x80) ? -(256 - dl) : dl));\n                                programCounter = (ushort)((programCounter & 0xFF00) | (byte)((programCounter & 0xFF) + dl));\n                                addressBus = programCounter;\n                                if ((temporaryAddress & 0xFF00) == (programCounter & 0xFF00))\n                                {\n                                    CompleteOperation();\n                                }\n                                break;\n                            case 3: // read from address\n                                PollInterrupts_CantDisableIRQ(); // If the first poll detected an IRQ, this second poll should not be allowed to un-set the IRQ.\n                                Fetch(addressBus); // dummy read\n                                programCounter = (ushort)((programCounter & 0xFF) | (temporaryAddress & 0xFF00));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x51: //(EOR), Y\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffY(true);\n                                break;\n                            case 5: // read from address\n                                PollInterrupts();\n                                Op_EOR(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x52: ///HLT ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                dl = Fetch(addressBus);\n                                break;\n                            case 2:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 3:\n                            case 4:\n                                addressBus = 0xFFFE;\n                                Fetch(addressBus);\n                                break;\n                            case 5:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 6:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                operationCycle = 5; //makes this loop infinitely.\n                                break;\n                        }\n                        break;\n\n                    case 0x53: //(SRE) Y ***\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffY(false);\n                                break;\n                            case 5: // dummy read\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 6: // dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 7: // read from address\n                                PollInterrupts();\n                                Op_SRE(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x54: //DOP ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Fetch(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x55: //EOR zp , X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Op_EOR(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x56: //LSR zp, X\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Op_LSR(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x57: //SRE zp X ***\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Op_SRE(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x58: //CLI\n                        PollInterrupts();\n                        Fetch(addressBus); // dummy read\n                        flag_Interrupt = false;\n                        CompleteOperation();\n                        break;\n\n                    case 0x59: //EOR Abs Y\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffY(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Op_EOR(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x5A: //NOP ***\n                        PollInterrupts();\n                        addressBus = programCounter; Fetch(addressBus);\n                        CompleteOperation();\n                        break;\n\n                    case 0x5B: //SRE abs, Y ***\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressAbsOffY(false);\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5:// dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 6:// read from address\n                                PollInterrupts();\n                                Op_SRE(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x5C: //TOP ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffX(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Fetch(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x5D: //EOR Abs, X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffX(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Op_EOR(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x5E: //LSR abs, X\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressAbsOffX(false);\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5:// dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 6:// read from address\n                                PollInterrupts();\n                                Op_LSR(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x5F: //SRE abs, X ***\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressAbsOffX(false);\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5:// dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 6:// read from address\n                                PollInterrupts();\n                                Op_SRE(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x60: //RTS\n\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetImmediate();\n                                break;\n                            case 2:\n                                addressBus = (ushort)(0x100 | stackPointer);\n                                Fetch(addressBus);\n                                addressBus = (ushort)((byte)(addressBus + 1) | 0x100);\n                                break;\n                            case 3:\n                                dl = Fetch(addressBus);\n                                programCounter = (ushort)((programCounter & 0xFF00) | dl); //technically not accurate, as this happens in cycle 5\n                                addressBus = (ushort)((byte)(addressBus + 1) | 0x100);\n                                break;\n                            case 4:\n                                dl = Fetch(addressBus);\n                                programCounter = (ushort)((programCounter & 0xFF) | (dl << 8));\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                stackPointer = (byte)addressBus;\n                                GetImmediate();\n                                CompleteOperation();\n                                break;\n\n                        }\n                        break;\n\n                    case 0x61: //(ADC X)\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffX();\n                                break;\n                            case 5: // read from address\n                                PollInterrupts();\n                                Op_ADC(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x62: ///HLT ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                dl = Fetch(addressBus);\n                                break;\n                            case 2:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 3:\n                            case 4:\n                                addressBus = 0xFFFE;\n                                Fetch(addressBus);\n                                break;\n                            case 5:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 6:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                operationCycle = 5; //makes this loop infinitely.\n                                break;\n                        }\n                        break;\n\n                    case 0x63: //(RRA X) ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffX();\n                                break;\n                            case 5: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 6: // write back to the address\n                                Store(dl, addressBus);\n                                break; // perform the operation\n                            case 7:\n                                PollInterrupts();\n                                Op_RRA(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x64: //DOP ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                PollInterrupts();\n                                Fetch(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x65: //ADC Zp\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                PollInterrupts();\n                                Op_ADC(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x66: //ROR zp\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 3: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 4: // perform operation\n                                PollInterrupts();\n                                Op_ROR(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x67: //RRA zp ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 3: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 4: // perform operation\n                                PollInterrupts();\n                                Op_RRA(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n                    case 0x68: //PLA\n\n                        switch (operationCycle)\n                        {\n                            case 1: //dummy fetch\n                                addressBus = programCounter;\n                                Fetch(addressBus);\n                                break;\n                            case 2: // read from address\n                                addressBus = (ushort)(0x100 | (stackPointer));\n                                Fetch(addressBus); // dummy read\n                                stackPointer++;\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                addressBus = (ushort)(0x100 | (stackPointer));\n                                A = Fetch(addressBus);\n                                flag_Zero = A == 0;\n                                flag_Negative = A >= 0x80;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x69: //ADC Imm\n                        PollInterrupts();\n                        GetImmediate();\n                        Op_ADC(dl);\n                        CompleteOperation();\n                        break;\n\n                    case 0x6A: //ROR A\n                        PollInterrupts();\n                        Fetch(addressBus); // dummy read\n                        Op_ROR_A();\n                        CompleteOperation();\n                        break;\n\n                    case 0x6B: // ARR ***\n                        PollInterrupts();\n                        GetImmediate();\n                        A = (byte)(A & dl);\n                        Op_ROR_A();\n                        flag_Zero = A == 0;\n                        flag_Carry = ((A & 0x40) >> 6) == 1;\n                        flag_Overflow = (((A & 0x20) >> 5) ^ ((A & 0x40) >> 6)) == 1;\n                        flag_Negative = A >= 0x80;\n                        CompleteOperation();\n                        break;\n\n                    case 0x6C: //JMP (indirect)\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3:\n                                specialBus = Fetch(addressBus); // Okay, this doesn't actually use the SB register. I'm just reusing that variable.\n                                break;\n                            case 4:\n                                PollInterrupts();\n                                dl = Fetch((ushort)((addressBus & 0xFF00) | (byte)(addressBus + 1)));\n                                programCounter = (ushort)((dl << 8) | specialBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x6D: //ADC Abs\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Op_ADC(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x6E: //ROR Abs\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Op_ROR(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x6F: //RRA Abs ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Op_RRA(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x70: //BVS\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                PollInterrupts();\n                                GetImmediate();\n                                if (!flag_Overflow)\n                                {\n                                    CompleteOperation();\n                                }\n                                break;\n                            case 2:\n                                Fetch(addressBus); // dummy read\n                                temporaryAddress = (ushort)(programCounter + ((dl >= 0x80) ? -(256 - dl) : dl));\n                                programCounter = (ushort)((programCounter & 0xFF00) | (byte)((programCounter & 0xFF) + dl));\n                                addressBus = programCounter;\n                                if ((temporaryAddress & 0xFF00) == (programCounter & 0xFF00))\n                                {\n                                    CompleteOperation();\n                                }\n                                break;\n                            case 3: // read from address\n                                PollInterrupts_CantDisableIRQ(); // If the first poll detected an IRQ, this second poll should not be allowed to un-set the IRQ.\n                                Fetch(addressBus); // dummy read\n                                programCounter = (ushort)((programCounter & 0xFF) | (temporaryAddress & 0xFF00));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x71: //(ADC), Y\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffY(true);\n                                break;\n                            case 5: // read from address\n                                PollInterrupts();\n                                Op_ADC(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x72: ///HLT ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                dl = Fetch(addressBus);\n                                break;\n                            case 2:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 3:\n                            case 4:\n                                addressBus = 0xFFFE;\n                                Fetch(addressBus);\n                                break;\n                            case 5:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 6:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                operationCycle = 5; //makes this loop infinitely.\n                                break;\n                        }\n                        break;\n\n                    case 0x73: //(RRA) Y ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffY(false);\n                                break;\n                            case 5: // dummy read\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 6: // dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 7: // read from address\n                                PollInterrupts();\n                                Op_RRA(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x74: //DOP ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Fetch(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x75: //ADC Zp, X\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Op_ADC(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x76: //ROR zp, X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Op_ROR(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x77: //RRA zp X ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Op_RRA(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x78: //SEI\n                        PollInterrupts();\n                        Fetch(addressBus); // dummy read\n                        flag_Interrupt = true;\n                        CompleteOperation();\n                        break;\n                    case 0x79: //ADC Abs, Y\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffY(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Op_ADC(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x7A: //NOP ***\n                        PollInterrupts();\n                        addressBus = programCounter;\n                        Fetch(addressBus);\n                        CompleteOperation();\n                        break;\n\n                    case 0x7B: //RRA Abs, Y ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressAbsOffY(false);\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5:// dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 6:// read from address\n                                PollInterrupts();\n                                Op_RRA(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x7C: //TOP ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffX(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Fetch(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x7D: //ADC Abs, X\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffX(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Op_ADC(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x7E: //ROR Abs, X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressAbsOffX(false);\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5:// dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 6:// read from address\n                                PollInterrupts();\n                                Op_ROR(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x7F: //RRA Abs, X ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressAbsOffX(false);\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5:// dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 6:// read from address\n                                PollInterrupts();\n                                Op_RRA(dl, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x80: //DOP ***\n                        PollInterrupts();\n                        GetImmediate();\n                        CompleteOperation();\n                        break;\n\n\n                    case 0x81: //(STA X)\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffX();\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5: // read from address\n                                PollInterrupts();\n                                Store(A, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x82: //DOP ***\n                        PollInterrupts();\n                        GetImmediate();\n                        CompleteOperation();\n                        break;\n\n                    case 0x83: //(SAX X)\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffX();\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5: // read from address\n                                PollInterrupts();\n                                Store((byte)(A & X), addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x84: //STY zp\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                CPU_Read = false;\n                                break;\n                            case 2: // read from address\n                                PollInterrupts();\n                                Store(Y, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x85: //STA zp\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                CPU_Read = false;\n                                break;\n                            case 2:\n                                PollInterrupts();\n                                Store(A, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x86: //STX zp\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                CPU_Read = false;\n                                break;\n                            case 2:\n                                PollInterrupts();\n                                Store(X, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n                    case 0x87: //SAX zp\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                CPU_Read = false;\n                                break;\n                            case 2:\n                                PollInterrupts();\n                                Store((byte)(A & X), addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x88: //DEY\n\n                        PollInterrupts();\n                        Y--;\n                        flag_Zero = Y == 0;\n                        flag_Negative = Y >= 0x80;\n                        Fetch(addressBus); // dummy read\n                        CompleteOperation();\n\n                        break;\n\n                    case 0x89: //DOP ***\n                        PollInterrupts();\n                        GetImmediate();\n                        CompleteOperation();\n\n                        break;\n\n                    case 0x8A: //TXA\n                        PollInterrupts();\n                        A = X;\n                        flag_Zero = A == 0;\n                        flag_Negative = A >= 0x80;\n                        Fetch(addressBus); // dummy read\n                        CompleteOperation();\n                        break;\n\n                    case 0x8B: //ANE\n                        PollInterrupts();\n                        GetImmediate();\n                        //A = (((A | 0xFF) & X) & temp); \n                        // Magic = FF\n                        A = (byte)((A | 0xFF) & X & dl); // 0xEE is also known as \"MAGIC\", and can supposedly be different depending on the CPU's temperature.\n                        flag_Zero = A == 0;\n                        flag_Negative = A >= 0x80;\n                        CompleteOperation();\n                        break;\n\n                    case 0x8C: //STY Abs\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                if (operationCycle == 2) { CPU_Read = false; }\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Store(Y, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x8D: //STA Abs\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                if (operationCycle == 2) { CPU_Read = false; }\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Store(A, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x8E: //STX Abs\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                if (operationCycle == 2) { CPU_Read = false; }\n                                break;\n                            case 3:\n                                PollInterrupts();\n                                Store(X, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x8F: //SAX Abs\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                if (operationCycle == 2) { CPU_Read = false; }\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Store((byte)(A & X), addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x90: //BCC\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                PollInterrupts();\n                                GetImmediate();\n                                if (flag_Carry)\n                                {\n                                    CompleteOperation();\n                                }\n                                break;\n                            case 2:\n                                Fetch(addressBus); // dummy read\n                                temporaryAddress = (ushort)(programCounter + ((dl >= 0x80) ? -(256 - dl) : dl));\n                                programCounter = (ushort)((programCounter & 0xFF00) | (byte)((programCounter & 0xFF) + dl));\n                                addressBus = programCounter;\n                                if ((temporaryAddress & 0xFF00) == (programCounter & 0xFF00))\n                                {\n                                    CompleteOperation();\n                                }\n                                break;\n                            case 3: // read from address\n                                PollInterrupts_CantDisableIRQ(); // If the first poll detected an IRQ, this second poll should not be allowed to un-set the IRQ.\n                                Fetch(addressBus); // dummy read\n                                programCounter = (ushort)((programCounter & 0xFF) | (temporaryAddress & 0xFF00));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x91: //(STA), Y\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffY(false);\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Store(A, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x92: ///HLT ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                dl = Fetch(addressBus);\n                                break;\n                            case 2:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 3:\n                            case 4:\n                                addressBus = 0xFFFE;\n                                Fetch(addressBus);\n                                break;\n                            case 5:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 6:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                operationCycle = 5; //makes this loop infinitely.\n                                break;\n                        }\n                        break;\n\n                    case 0x93: // (SHA) Y ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffY(false);\n                                if (operationCycle == 4)\n                                {\n                                    CPU_Read = false;\n                                }\n                                break;\n                            case 5: // read from address\n                                PollInterrupts();\n                                if ((temporaryAddress & 0xFF00) != (addressBus & 0xFF00))\n                                {\n                                    // if adding Y to the target address crossed a page boundary, this opcode has \"gone unstable\"\n                                    addressBus = (ushort)((byte)addressBus | ((addressBus >> 8) /*& A*/ & X) << 8); // Alternate SHA behavior. The A register isn't used here!\n                                }\n                                // pd = the high byte of the target address + 1\n                                if (IgnoreH)\n                                {\n                                    H = 0xFF;\n                                }\n                                Store((byte)(A & (X | 0xF5) & H), addressBus); // Alternate SHA behavior. X is ORed with a magic number. On my console, it's $F5 for a few hours, then it flickers from $F5 and $FD.\n                                CompleteOperation();\n                                break;\n                        }\n\n\n                        break;\n\n                    case 0x94: //STY zp, X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                if (operationCycle == 2) { CPU_Read = false; }\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Store(Y, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x95: //STA zp, X\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                if (operationCycle == 2) { CPU_Read = false; }\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Store(A, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x96: //STX zp, Y\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffY();\n                                if (operationCycle == 2) { CPU_Read = false; }\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Store(X, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x97: //SAX zp, Y\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffY();\n                                if (operationCycle == 2) { CPU_Read = false; }\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Store((byte)(A & X), addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x98: //TYA\n                        PollInterrupts();\n                        A = Y;\n                        Fetch(addressBus); // dummy read\n                        flag_Zero = A == 0;\n                        flag_Negative = A >= 0x80;\n                        CompleteOperation();\n\n                        break;\n\n                    case 0x99: //STA Abs, Y\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffY(false);\n                                if (operationCycle == 3) { CPU_Read = false; }\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Store(A, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x9A: //TXS\n                        PollInterrupts();\n                        stackPointer = X;\n                        Fetch(addressBus); // dummy read\n                        CompleteOperation();\n                        break;\n\n\n                    case 0x9B: //SHS, Abs Y ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffY(false);\n                                if (operationCycle == 3) { CPU_Read = false; }\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                if ((temporaryAddress & 0xFF00) != (addressBus & 0xFF00))\n                                {\n                                    // if adding Y to the target address crossed a page boundary, this opcode has \"gone unstable\"\n                                    addressBus = (ushort)((byte)addressBus | ((addressBus >> 8) /*& A*/ & X) << 8); // Alternate SHS behavior. The A register isn't used here!\n                                }\n                                // pd = the high byte of the target address + 1\n                                stackPointer = (byte)(A & X);\n                                if (IgnoreH)\n                                {\n                                    H = 0xFF;\n                                }\n                                Store((byte)(A & (X | 0xF5) & H), addressBus); // Alternate SHS behavior. X is ORed with a magic number. On my console, it's $F5 for a few hours, then it flickers from $F5 and $FD.\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x9C: //SHY Abs, X ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffX(false);\n                                if (operationCycle == 3) { CPU_Read = false; }\n                                break;\n                            case 4:\n                                PollInterrupts();\n                                if ((temporaryAddress & 0xFF00) != (addressBus & 0xFF00))\n                                {\n                                    // if adding X to the target address crossed a page boundary, this opcode has \"gone unstable\"\n                                    addressBus = (ushort)((byte)addressBus | ((addressBus >> 8) & Y) << 8);\n                                }\n                                if (IgnoreH)\n                                {\n                                    H = 0xFF;\n                                }\n                                Store((byte)(Y & H), addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x9D: //STA Abs, X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffX(false);\n                                if (operationCycle == 3) { CPU_Read = false; }\n                                break;\n                            case 4:\n                                PollInterrupts();\n                                Store(A, addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x9E: // SHX Abs, Y***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffY(false);\n                                if (operationCycle == 3) { CPU_Read = false; }\n                                break;\n                            case 4:\n                                PollInterrupts();\n                                // Not even close to what the documentation says this instruction does.\n                                if ((temporaryAddress & 0xFF00) != (addressBus & 0xFF00))\n                                {\n                                    // if adding Y to the target address crossed a page boundary, this opcode has \"gone unstable\"\n                                    addressBus = (ushort)((byte)addressBus | ((addressBus >> 8) & X) << 8);\n                                }\n                                if (IgnoreH)\n                                {\n                                    H = 0xFF;\n                                }\n                                Store((byte)(X & H), addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0x9F: // SHA Abs, Y***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffY(false);\n                                if (operationCycle == 3) { CPU_Read = false; }\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                if ((temporaryAddress & 0xFF00) != (addressBus & 0xFF00))\n                                {\n                                    // if adding Y to the target address crossed a page boundary, this opcode has \"gone unstable\"\n                                    addressBus = (ushort)((byte)addressBus | ((addressBus >> 8) /*& A*/ & X) << 8); // Alternate SHA behavior. The A register isn't used here!\n                                }\n                                if (IgnoreH)\n                                {\n                                    H = 0xFF;\n                                }\n                                Store((byte)(A & (X | 0xF5) & H), addressBus); // Alternate SHA behavior. X is ORed with a magic number. On my console, it's $F5 for a few hours, then it flickers from $F5 and $FD.\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xA0: //LDY imm\n                        PollInterrupts();\n                        GetImmediate();\n                        Y = dl;\n                        flag_Zero = Y == 0;\n                        flag_Negative = Y >= 0x80;\n                        CompleteOperation();\n\n                        break;\n\n                    case 0xA1: //(LDA, X)\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffX();\n                                break;\n                            case 5: // read from address\n                                PollInterrupts();\n                                A = Fetch(addressBus);\n                                flag_Zero = A == 0;\n                                flag_Negative = A >= 0x80;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xA2: //LDX imm\n                        PollInterrupts();\n                        GetImmediate();\n                        X = dl;\n                        flag_Zero = X == 0;\n                        flag_Negative = X >= 0x80;\n                        CompleteOperation();\n\n                        break;\n\n                    case 0xA3: //(LAX, X) ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffX();\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                A = Fetch(addressBus);\n                                X = A;\n                                flag_Zero = X == 0;\n                                flag_Negative = X >= 0x80;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xA4: //LDY zp\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                PollInterrupts();\n                                Y = Fetch(addressBus);\n                                flag_Zero = Y == 0;\n                                flag_Negative = Y >= 0x80;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xA5: //LDA zp\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                PollInterrupts();\n                                A = Fetch(addressBus);\n                                flag_Zero = A == 0;\n                                flag_Negative = A >= 0x80;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xA6: //LDX zp\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                PollInterrupts();\n                                X = Fetch(addressBus);\n                                flag_Zero = X == 0;\n                                flag_Negative = X >= 0x80;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xA7: //LAX zp ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                PollInterrupts();\n                                A = Fetch(addressBus);\n                                X = A;\n                                flag_Zero = X == 0;\n                                flag_Negative = X >= 0x80;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xA8: //TAY\n                        PollInterrupts();\n                        Y = A;\n                        Fetch(addressBus); // dummy read\n                        flag_Zero = A == 0;\n                        flag_Negative = Y >= 0x80;\n                        CompleteOperation();\n                        break;\n\n                    case 0xA9: //LDA Imm\n                        PollInterrupts();\n                        GetImmediate();\n                        A = dl;\n                        flag_Zero = A == 0;\n                        flag_Negative = A >= 0x80;\n                        CompleteOperation();\n                        break;\n\n                    case 0xAA: //TAX\n                        PollInterrupts();\n                        X = A;\n                        Fetch(addressBus); // dummy read\n                        flag_Zero = X == 0;\n                        flag_Negative = X >= 0x80;\n                        CompleteOperation();\n                        break;\n\n                    case 0xAB: //LXA ***\n                        PollInterrupts();\n                        GetImmediate();\n                        A = (byte)((A | 0xFF) & dl); // 0xEE is also known as \"MAGIC\", and can supposedly be different depending on the CPU's temperature.\n                        X = A;  // this instruction is basically XAA but using LAX behavior, so X is also affected..\n                        flag_Negative = X >= 0x80;\n                        flag_Zero = X == 0x00;\n                        CompleteOperation();\n                        break;\n\n                    case 0xAC: //LDY Abs\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Y = Fetch(addressBus);\n                                flag_Negative = Y >= 0x80;\n                                flag_Zero = Y == 0x00;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xAD: //LDA Abs\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                A = Fetch(addressBus);\n                                flag_Negative = A >= 0x80;\n                                flag_Zero = A == 0x00;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xAE: //LDX Abs\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                X = Fetch(addressBus);\n                                flag_Negative = X >= 0x80;\n                                flag_Zero = X == 0x00;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xAF: //LAX Abs ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                A = Fetch(addressBus);\n                                X = A;\n                                flag_Negative = X >= 0x80;\n                                flag_Zero = X == 0x00;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xB0: //BCS\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                PollInterrupts();\n                                GetImmediate();\n                                if (!flag_Carry)\n                                {\n                                    CompleteOperation();\n                                }\n                                break;\n                            case 2:\n                                Fetch(addressBus); // dummy read\n                                temporaryAddress = (ushort)(programCounter + ((dl >= 0x80) ? -(256 - dl) : dl));\n                                programCounter = (ushort)((programCounter & 0xFF00) | (byte)((programCounter & 0xFF) + dl));\n                                addressBus = programCounter;\n                                if ((temporaryAddress & 0xFF00) == (programCounter & 0xFF00))\n                                {\n                                    CompleteOperation();\n                                }\n                                break;\n                            case 3: // read from address\n                                PollInterrupts_CantDisableIRQ(); // If the first poll detected an IRQ, this second poll should not be allowed to un-set the IRQ.\n                                Fetch(addressBus); // dummy read\n                                programCounter = (ushort)((programCounter & 0xFF) | (temporaryAddress & 0xFF00));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xB1: //(LDA), Y\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffY(true);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                A = Fetch(addressBus);\n                                flag_Zero = A == 0;\n                                flag_Negative = A >= 0x80;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xB2: ///HLT ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                dl = Fetch(addressBus);\n                                break;\n                            case 2:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 3:\n                            case 4:\n                                addressBus = 0xFFFE;\n                                Fetch(addressBus);\n                                break;\n                            case 5:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 6:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                operationCycle = 5; //makes this loop infinitely.\n                                break;\n                        }\n                        break;\n\n                    case 0xB3: //(LAX), Y ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffY(true);\n                                break;\n                            case 5: // read from address\n                                PollInterrupts();\n                                A = Fetch(addressBus);\n                                X = A;\n                                flag_Zero = X == 0;\n                                flag_Negative = X >= 0x80;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n                    case 0xB4: //LDY zp, X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Y = Fetch(addressBus);\n                                flag_Zero = Y == 0;\n                                flag_Negative = Y >= 0x80;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xB5: //LDA zp, X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                A = Fetch(addressBus);\n                                flag_Zero = A == 0;\n                                flag_Negative = A >= 0x80;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xB6: //LDX zp,  Y\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffY();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                X = Fetch(addressBus);\n                                flag_Zero = X == 0;\n                                flag_Negative = X >= 0x80;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xB7: //LAX zp, Y ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffY();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                A = Fetch(addressBus);\n                                X = A;\n                                flag_Zero = X == 0;\n                                flag_Negative = X >= 0x80;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xB8: //CLV\n                        PollInterrupts();\n                        Fetch(addressBus); // dummy read\n                        flag_Overflow = false;\n                        CompleteOperation();\n                        break;\n\n                    case 0xB9: //LDA abs , Y\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffY(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                A = Fetch(addressBus);\n                                flag_Zero = A == 0;\n                                flag_Negative = A >= 0x80;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xBA: //TSX\n\n                        PollInterrupts();\n                        X = stackPointer;\n                        Fetch(addressBus); // dummy read\n                        flag_Negative = X >= 0x80;\n                        flag_Zero = X == 0;\n                        CompleteOperation();\n                        break;\n\n                    case 0xBB: //LAE Abs, Y***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffY(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                dl = Fetch(addressBus);\n                                A = (byte)(dl & stackPointer);\n                                X = (byte)(dl & stackPointer);\n                                stackPointer = (byte)(dl & stackPointer);\n                                flag_Negative = X >= 0x80;\n                                flag_Zero = X == 0;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xBC: //LDY abs, X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffX(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Y = Fetch(addressBus);\n                                flag_Negative = Y >= 0x80;\n                                flag_Zero = Y == 0;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n\n                    case 0xBD: //LDA abs, X\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffX(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                A = Fetch(addressBus);\n                                flag_Negative = A >= 0x80;\n                                flag_Zero = A == 0;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xBE: //LDX abs , Y\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffY(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                X = Fetch(addressBus);\n                                flag_Negative = X >= 0x80;\n                                flag_Zero = X == 0;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xBF: //LAX Abs, Y ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffY(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                A = Fetch(addressBus);\n                                X = A;\n                                flag_Negative = X >= 0x80;\n                                flag_Zero = X == 0;\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xC0: //CPY Imm\n                        PollInterrupts();\n                        GetImmediate();\n                        Op_CPY(dl);\n                        CompleteOperation();\n\n                        break;\n\n                    case 0xC1: //(CMP X),\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffX();\n                                break;\n                            case 5: // read from address\n                                PollInterrupts();\n                                Op_CMP(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xC2: //DOP ***\n                        PollInterrupts();\n                        GetImmediate();\n                        CompleteOperation();\n\n                        break;\n\n                    case 0xC3: //(DCP, X) ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffX();\n                                break;\n                            case 5: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 6: // write back to the address\n                                Store(dl, addressBus);\n                                break; // perform the operation\n                            case 7:\n                                PollInterrupts();\n                                dl--;\n                                Store(dl, addressBus);\n                                Op_CMP(dl);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xC4: //CPY zp\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                PollInterrupts();\n                                Op_CPY(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xC5: //CMP zp\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                PollInterrupts();\n                                Op_CMP(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xC6: //DEC zp\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2:\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 3:\n                                Store(dl, addressBus); //dummy write\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Op_DEC(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xC7: //DCP zp ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2:\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 3:\n                                Store(dl, addressBus); //dummy write\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Op_DEC(addressBus);\n                                Op_CMP(dl);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n\n                    case 0xC8: //INY\n                        PollInterrupts();\n                        Y++;\n                        Fetch(addressBus); // dummy read\n                        flag_Zero = Y == 0;\n                        flag_Negative = Y >= 0x80;\n                        CompleteOperation();\n                        break;\n\n                    case 0xC9: //CMP Imm\n                        PollInterrupts();\n                        GetImmediate();\n                        Op_CMP(dl);\n                        CompleteOperation();\n                        break;\n\n                    case 0xCA: //DEX\n                        PollInterrupts();\n                        X--;\n                        Fetch(addressBus); // dummy read\n                        flag_Zero = X == 0;\n                        flag_Negative = X >= 0x80;\n                        CompleteOperation();\n\n                        break;\n\n                    case 0xCB: // AXS ***\n                        PollInterrupts();\n                        GetImmediate();\n                        X = (byte)(X & A);\n                        flag_Carry = X >= dl;\n                        X -= dl;\n                        flag_Zero = X == 0;\n                        flag_Negative = (X >= 0x80);\n\n                        CompleteOperation();\n                        break;\n\n\n                    case 0xCC: //CPY Abs\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Op_CPY(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xCD: //CMP Abs\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Op_CMP(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xCE: //DEC Abs\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3:\n                                // dummy read\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4:\n                                // dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5: // write\n                                PollInterrupts();\n                                Op_DEC(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xCF: //DCP Abs ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3:\n                                // dummy read\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4:\n                                // dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5: // write\n                                PollInterrupts();\n                                Op_DEC(addressBus);\n                                Op_CMP(dl);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xD0: //BNE\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                PollInterrupts();\n                                GetImmediate();\n                                if (flag_Zero)\n                                {\n                                    CompleteOperation();\n                                }\n                                break;\n                            case 2:\n                                Fetch(addressBus); // dummy read\n                                temporaryAddress = (ushort)(programCounter + ((dl >= 0x80) ? -(256 - dl) : dl));\n                                programCounter = (ushort)((programCounter & 0xFF00) | (byte)((programCounter & 0xFF) + dl));\n                                addressBus = programCounter;\n                                if ((temporaryAddress & 0xFF00) == (programCounter & 0xFF00))\n                                {\n                                    CompleteOperation();\n                                }\n                                break;\n                            case 3: // read from address\n                                PollInterrupts_CantDisableIRQ(); // If the first poll detected an IRQ, this second poll should not be allowed to un-set the IRQ.\n                                Fetch(addressBus); // dummy read\n                                programCounter = (ushort)((programCounter & 0xFF) | (temporaryAddress & 0xFF00));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xD1: //(CMP), Y\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffY(true);\n                                break;\n                            case 5: // read from address\n                                PollInterrupts();\n                                Op_CMP(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xD2: ///HLT ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                dl = Fetch(addressBus);\n                                break;\n                            case 2:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 3:\n                            case 4:\n                                addressBus = 0xFFFE;\n                                Fetch(addressBus);\n                                break;\n                            case 5:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 6:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                operationCycle = 5; //makes this loop infinitely.\n                                break;\n                        }\n                        break;\n\n                    case 0xD3: //(DCP) Y ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffY(false);\n                                break;\n                            case 5: // dummy read\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 6: // dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 7: // read from address\n                                PollInterrupts();\n                                Op_DEC(addressBus);\n                                Op_CMP(dl);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xD4: //DOP ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Fetch(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xD5: //CMP zp, X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Op_CMP(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xD6: //DEC zp, X\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3:\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4:\n                                Store(dl, addressBus); //dummy write\n                                break;\n                            case 5: // read from address\n                                PollInterrupts();\n                                Op_DEC(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xD7: //DCP Zp X ***\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3:\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4:\n                                Store(dl, addressBus); //dummy write\n                                break;\n                            case 5: // read from address\n                                PollInterrupts();\n                                Op_DEC(addressBus);\n                                Op_CMP(dl);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xD8: //CLD\n                        PollInterrupts();\n                        Fetch(addressBus); // dummy read\n                        flag_Decimal = false;\n                        CompleteOperation();\n\n                        break;\n                    case 0xD9: //CMP abs, Y\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffY(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Op_CMP(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xDA: //NOP ***\n                        PollInterrupts();\n                        Fetch(addressBus); // dummy read\n                        CompleteOperation();\n                        break;\n\n                    case 0xDB: //DCP Abs Y ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressAbsOffY(false);\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5:// dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 6:// read from address\n                                PollInterrupts();\n                                Op_DEC(addressBus);\n                                Op_CMP(dl);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xDC: //TOP ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffX(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Fetch(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xDD: //CMP abs, X\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffX(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Op_CMP(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xDE: //DEC Abs X\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressAbsOffX(false);\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5:// dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 6:// read from address\n                                PollInterrupts();\n                                Op_DEC(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xDF: //DCP Abs X ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressAbsOffX(false);\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5:// dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 6:// read from address\n                                PollInterrupts();\n                                Op_DEC(addressBus);\n                                Op_CMP(dl);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xE0: //CPX Imm\n                        PollInterrupts();\n                        GetImmediate();\n                        Op_CPX(dl);\n                        CompleteOperation();\n                        break;\n\n                    case 0xE1: //(SBC X)\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffX();\n                                break;\n                            case 5: // read from address\n                                PollInterrupts();\n                                Op_SBC(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xE2: //DOP ***\n                        PollInterrupts();\n                        GetImmediate();\n                        CompleteOperation();\n                        break;\n\n                    case 0xE3: //(ISC, X) ***\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffX();\n                                break;\n                            case 5: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 6: // write back to the address\n                                Store(dl, addressBus);\n                                break; // perform the operation\n                            case 7:\n                                PollInterrupts();\n                                Op_INC(addressBus);\n                                Op_SBC(dl);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xE4: //CPX zp\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                PollInterrupts();\n                                Op_CPX(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xE5: //SBC Zp\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                PollInterrupts();\n                                Op_SBC(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xE6: //INC zp\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 3: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 4: // perform operation\n                                PollInterrupts();\n                                Op_INC(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xE7: //ISC zp ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                GetAddressZeroPage();\n                                break;\n                            case 2: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 3: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 4: // perform operation\n                                PollInterrupts();\n                                Op_INC(addressBus);\n                                Op_SBC(dl);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xE8: //INX\n                        PollInterrupts();\n                        Fetch(addressBus); // dummy read\n                        X++;\n                        flag_Zero = X == 0;\n                        flag_Negative = X >= 0x80;\n                        CompleteOperation();\n                        break;\n\n                    case 0xE9: //SBC Imm\n                        PollInterrupts();\n                        GetImmediate();\n                        Op_SBC(dl);\n                        CompleteOperation();\n                        break;\n\n                    case 0xEA: //NOP\n                        PollInterrupts();\n                        Fetch(addressBus); // dummy read\n                        CompleteOperation();\n                        break;\n\n                    case 0xEB: //SBC Imm ***\n                        PollInterrupts();\n                        GetImmediate();\n                        Op_SBC(dl);\n                        CompleteOperation();\n                        break;\n\n                    case 0xEC: //CPX Abs\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Op_CPX(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xED: //SBC Abs\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Op_SBC(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xEE: //INC Abs\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                if (addressBus == 0x4014)\n                                {\n\n                                }\n                                break;\n                            case 3: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Op_INC(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xEF: //ISC Abs ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressAbsolute();\n                                break;\n                            case 3: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Op_INC(addressBus);\n                                Op_SBC(dl);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xF0: //BEQ\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                PollInterrupts();\n                                GetImmediate();\n                                if (!flag_Zero)\n                                {\n                                    CompleteOperation();\n                                }\n                                break;\n                            case 2:\n                                Fetch(addressBus); // dummy read\n                                temporaryAddress = (ushort)(programCounter + ((dl >= 0x80) ? -(256 - dl) : dl));\n                                programCounter = (ushort)((programCounter & 0xFF00) | (byte)((programCounter & 0xFF) + dl));\n                                addressBus = programCounter;\n                                if ((temporaryAddress & 0xFF00) == (programCounter & 0xFF00))\n                                {\n                                    CompleteOperation();\n                                }\n                                break;\n                            case 3: // read from address\n                                PollInterrupts_CantDisableIRQ(); // If the first poll detected an IRQ, this second poll should not be allowed to un-set the IRQ.\n                                Fetch(addressBus); // dummy read\n                                programCounter = (ushort)((programCounter & 0xFF) | (temporaryAddress & 0xFF00));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xF1: //(SBC) Y\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffY(true);\n                                break;\n                            case 5: // read from address\n                                PollInterrupts();\n                                Op_SBC(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xF2: ///HLT ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                                dl = Fetch(addressBus);\n                                break;\n                            case 2:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 3:\n                            case 4:\n                                addressBus = 0xFFFE;\n                                Fetch(addressBus);\n                                break;\n                            case 5:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                break;\n                            case 6:\n                                addressBus = 0xFFFF;\n                                Fetch(addressBus);\n                                operationCycle = 5; //makes this loop infinitely.\n                                break;\n                        }\n                        break;\n\n                    case 0xF3: //(ISC) Y\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressIndOffY(false);\n                                break;\n                            case 5: // dummy read\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 6: // dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 7: // read from address\n                                PollInterrupts();\n                                Op_INC(addressBus);\n                                Op_SBC(dl);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xF4: //DOP ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Fetch(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xF5: //SBC Zp, X\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                PollInterrupts();\n                                Op_SBC(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xF6: //INC Zp, X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Op_INC(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xF7: //ISC zp, X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                                GetAddressZPOffX();\n                                break;\n                            case 3: // read from address\n                                dl = Fetch(addressBus);\n                                CPU_Read = false;\n                                break;\n                            case 4: //dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 5:\n                                PollInterrupts();\n                                Op_INC(addressBus);\n                                Op_SBC(dl);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xF8: //SED\n                        PollInterrupts();\n                        Fetch(addressBus); // dummy read\n                        flag_Decimal = true;\n                        CompleteOperation();\n                        break;\n\n                    case 0xF9: //SBC Abs Y\n\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffY(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Op_SBC(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xFA: //NOP ***\n                        PollInterrupts();\n                        Fetch(addressBus); // dummy read\n                        CompleteOperation();\n                        break;\n\n                    case 0xFB: //ISC Abs Y ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressAbsOffY(false);\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5:// dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 6:// read from address\n                                PollInterrupts();\n                                Op_INC(addressBus);\n                                Op_SBC(dl);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xFC: //TOP ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffX(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Fetch(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xFD: //SBC Abs, X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                                GetAddressAbsOffX(true);\n                                break;\n                            case 4: // read from address\n                                PollInterrupts();\n                                Op_SBC(Fetch(addressBus));\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xFE: //INC Abs, X\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressAbsOffX(false);\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5:// dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 6:// read from address\n                                PollInterrupts();\n                                Op_INC(addressBus);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n\n                    case 0xFF: //ISC Abs, X ***\n                        switch (operationCycle)\n                        {\n                            case 1:\n                            case 2:\n                            case 3:\n                            case 4:\n                                GetAddressAbsOffX(false);\n                                if (operationCycle == 4) { CPU_Read = false; }\n                                break;\n                            case 5:// dummy write\n                                Store(dl, addressBus);\n                                break;\n                            case 6:// read from address\n                                PollInterrupts();\n                                Op_INC(addressBus);\n                                Op_SBC(dl);\n                                CompleteOperation();\n                                break;\n                        }\n                        break;\n                    // And that's all 256 instructions!\n                }\n                operationCycle++; // increment this for next CPU cycle.\n            }\n            if (DoDMCDMA && APU_ImplicitAbortDMC4015)\n            {\n                APU_ImplicitAbortDMC4015 = false; // If this was delayed by a write cycle, it won't run at all.\n            }\n        }\n\n\n        public void ResetReadPush()\n        {\n            // the RESET instruction has unique behavior where it reads from the stack, and decrements the stack pointer.\n            Fetch((ushort)(0x100 + stackPointer));\n            stackPointer--;\n        }\n\n        public void Push(byte A)\n        {\n            // Store to the stack, and decrement the stack pointer.\n            Store(A, (ushort)(0x100 + stackPointer));\n            stackPointer--;\n        }\n\n        // I don't have a void for pop... All instructions that pull form the stack just perform the logic.\n\n\n        ushort PPU_VRAM_MysteryAddress; // used during consecutive write cycles to VRAM. The PPU makes 2 extra writes to VRAM, and one of them I call \"the mystery write\".\n\n        public ushort PPU_AddressBus;  // the Address Bus of the PPU\n        public bool PPU_ALE; // Address Latch Enable\n        public byte PPU_OctalLatch; // This is the address latch.\n\n        public ushort PPU_v = 0;// PPU Internal Register 'v'\n        public ushort PPU_t = 0; // PPU Internal Register 't'. \"can also be thought of as the address of the top left onscreen tile: https://www.nesdev.org/wiki/PPU_scrolling\"\n        /*\n        The v and t registers are 15 bits:\n        yyy NN YYYYY XXXXX\n        ||| || ||||| +++++-- coarse X scroll\n        ||| || +++++-------- coarse Y scroll\n        ||| ++-------------- nametable select\n        +++----------------- fine Y scroll\n        */\n\n        byte PPU_Update2006Delay;   // The number of PPU cycles to wait between writing to $2006 and the ppu from updating\n        byte PPU_Update2005Delay;   // The number of PPU cycles to wait between writing to $2004 and the ppu from updating\n        byte PPU_Update2005Value;   // The value written to $2005, for use when the delay has ended.\n        byte PPU_Update2001Value;   // The value written to $2001, for use when the delay has ended.\n        ushort PPU_Update2006Value;   // The value written to $2006, for use when the delay has ended.\n        ushort PPU_Update2006Value_Temp;\n\n        byte PPU_Update2001Delay;   // The number of PPU cycles to wait between writing to $2001 and the ppu from updating\n        byte PPU_Update2001OAMCorruptionDelay; // I plan to refactor 2001 writes and remove the hard-coded delays. This will be removed eventually.\n        byte PPU_Update2001EmphasisBitsDelay; //  I plan to refactor 2001 writes and remove the hard-coded delays. This will be removed eventually.\n\n        bool PPU_WasRenderingBefore2001Write; // Were we rendering before writing to $2001? (used for OAM corruption)\n\n        byte PPU_ReadBuffer = 0; // when reading from $2007, this buffer holds the value from VRAM that gets read. Updated after reading from $2007.\n\n        bool PPUAddrLatch = false;  // Certain ppu registers take two writes to fully set things up. It's flipped when writing to $2005 and $2006. Reset when reading from $2002\n\n        bool PPUControlIncrementMode32; // Set by writing to $2000. If set, the VRAM address is incremented by 32 instead of 1 after reads/writes to $2007.\n        bool PPUControl_NMIEnabled;     // Set by writing to $2000. If set, the NMI can occur.\n\n        public bool PPU_PatternSelect_Sprites; //which pattern table is used for sprites / background\n        public bool PPU_PatternSelect_Background; //which pattern table is used for sprites / background\n        public bool PPU_EXT_Enable; // I can toggle this boolean, but it is otherwise unimplemented.\n\n        //for logging purposes. doesn't update databus.\n        bool DebugObserve = false;\n        public byte Observe(ushort Address)\n        {\n            // Reading from anywhere goes through this function.\n            if ((Address >= 0x8000))\n            {\n                // Reading from ROM.\n                // Different mappers could rearrange the data from the ROM into different locations on the system bus.\n                return MapperObserve(Address, Cart.MemoryMapper);\n            }\n            else if (Address < 0x2000)\n            {\n                // Reading from RAM.\n                // Ram mirroring! Only addresses $0000 through $07FF exist in RAM, so ignore bits 11 and 12\n                return RAM[Address & 0x7FF];\n            }\n            else if (Address >= 0x2000 && Address < 0x4000)\n            {\n                // PPU registers. most of these aren't meant to be read.\n                Address = (ushort)(Address & 0x2007);\n                switch (Address)\n                {\n                    case 0x2000:\n                        // Write only. Return the PPU databus.\n                        return PPUBus;\n                    case 0x2001:\n                        // Write only. Return the PPU databus.\n                        return PPUBus;\n                    case 0x2002:\n                        // PPU Flags.\n                        return (byte)((((PPUStatus_VBlank ? 0x80 : 0) | (PPUStatus_SpriteZeroHit ? 0x40 : 0) | (PPUStatus_SpriteOverflow ? 0x20 : 0)) & 0xE0) + (PPUBus & 0x1F));\n                    case 0x2003:\n                        // write only. Return the PPU databus.\n                        return PPUBus;\n                    case 0x2004:\n                        // Read from OAM\n                        return (byte)(ReadOAM());\n                    case 0x2005:\n                        // write only. Return the PPU databus.\n                        return PPUBus;\n                    case 0x2006:\n                        // write only. Return the PPU databus.\n                        return PPUBus;\n                    case 0x2007:\n                        // Reading from VRAM.\n                        return ObservePPU(PPU_v);\n                }\n\n            }\n            else if (Address >= 0x4000 && Address <= 0x401F) // observe the APU registers\n            {\n                //addressBus \n                byte Reg = (byte)(Address & 0x1F);\n                if (Reg == 0x15)\n                {\n\n                    byte InternalBus = dataBus;\n\n                    InternalBus &= 0x20;\n                    InternalBus |= (byte)(APU_Status_DMCInterrupt ? 0x80 : 0);\n                    InternalBus |= (byte)(APU_Status_FrameInterrupt ? 0x40 : 0);\n                    InternalBus |= (byte)((APU_DMC_BytesRemaining != 0 && APU_Status_DelayedDMC) ? 0x10 : 0); // see footnote.\n                    InternalBus |= (byte)((APU_LengthCounter_Noise != 0) ? 0x08 : 0);\n                    InternalBus |= (byte)((APU_LengthCounter_Triangle != 0) ? 0x04 : 0);\n                    InternalBus |= (byte)((APU_LengthCounter_Pulse2 != 0) ? 0x02 : 0);\n                    InternalBus |= (byte)((APU_LengthCounter_Pulse1 != 0) ? 0x01 : 0);\n                    return InternalBus; // reading from $4015 can not affect the databus\n                }\n                else if (Reg == 0x16 || Reg == 0x17)\n                {\n                    return (byte)((((Reg == 0x16) ? (ControllerShiftRegister1 & 0x80) : (ControllerShiftRegister2 & 0x80)) == 0 ? 0 : 1) | (dataBus & 0xE0));\n                }\n            }\n            else\n            {\n                //mapper chip stuff, but also open bus!\n                return MapperObserve(Address, Cart.MemoryMapper);\n            }\n\n            return dataBus;\n        }\n        public byte Fetch(ushort Address)\n        {\n            dataPinsAreNotFloating = false; // assume the data pins are floating by default.\n            // Reading from anywhere goes through this function.\n            if ((Address >= 0x8000))\n            {\n                // Reading from ROM.\n                // Different mappers could rearrange the data from the ROM into different locations on the system bus.\n                MapperFetch(Address, Cart.MemoryMapper);\n                dataPinsAreNotFloating = true;\n            }\n            else if (Address < 0x2000)\n            {\n                // Reading from RAM.\n                // Ram mirroring! Only addresses $0000 through $07FF exist in RAM, so ignore bits 11 and 12\n                dataBus = RAM[Address & 0x7FF];\n                dataPinsAreNotFloating = true;\n            }\n            else if (Address >= 0x2000 && Address < 0x4000)\n            {\n                // PPU registers. most of these aren't meant to be read.\n                Address = (ushort)(Address & 0x2007);\n                switch (Address)\n                {\n                    case 0x2000:\n                        // Write only. Return the PPU databus.\n                        dataBus = PPUBus;\n\n                        break;\n                    case 0x2001:\n                        // Write only. Return the PPU databus.\n                        dataBus = PPUBus;\n\n                        break;\n                    case 0x2002:\n                        // PPU Flags.\n\n                        dataBus = (byte)((((PPUStatus_VBlank ? 0x80 : 0)))); // The vblank flag is read at the start of the read...\n                        PPU_Read2002 = true;\n                        EmulateUntilEndOfRead();\n                        dataBus |= (byte)((((PPUStatus_SpriteZeroHit_Delayed ? 0x40 : 0) | (PPUStatus_SpriteOverflow_Delayed ? 0x20 : 0)) & 0xE0) + (PPUBus & 0x1F)); // ...while the sprite flags are read at the end.\n\n                        PPUAddrLatch = false;\n                        PPUBus = dataBus;\n                        for (int i = 5; i < 8; i++) { PPUBusDecay[i] = PPUBusDecayConstant; }\n\n                        break;\n                    case 0x2003:\n                        // write only. Return the PPU databus.\n                        dataBus = PPUBus; break;\n                    case 0x2004:\n                        // Read from OAM\n                        EmulateUntilEndOfRead();\n                        dataBus = ReadOAM();\n\n                        PPUBus = dataBus;\n                        for (int i = 0; i < 8; i++) { PPUBusDecay[i] = PPUBusDecayConstant; }\n\n                        break;\n                    case 0x2005:\n                        // write only. Return the PPU databus.\n                        dataBus = PPUBus; break;\n                    case 0x2006:\n                        // write only. Return the PPU databus.\n                        dataBus = PPUBus; break;\n                    case 0x2007:\n                        // Reading from VRAM.\n\n                        if ((PPU_AddressBus & 0x3FFF) >= 0x3F00)\n                        {\n                            // read from palette RAM.\n                            // Palette RAM only returns bits 0-5, so bits 6 and 7 are PPU open bus.\n                            ThisDotReadFromPaletteRAM = true;\n                            ushort PalRAMAddr = (ushort)(PPU_v & 0x3F1F);\n                            if ((PalRAMAddr & 3) == 0)\n                            {\n                                PalRAMAddr &= 0x3F0F;\n                            }\n\n                            dataBus = (byte)(((PaletteRAM[PalRAMAddr & 0x1F] & (PPU_Mask_Greyscale ? 0x30 : 0x3F)) | (PPUBus & 0xC0)));\n                        }\n                        else\n                        {\n                            dataBus = PPU_ReadBuffer;\n                        }\n                        PPUBus = dataBus;\n                        for (int i = 0; i < 8; i++) { PPUBusDecay[i] = PPUBusDecayConstant; }\n\n                        EmulateUntilEndOfRead();\n                        PPU_2007_Read_SR = true; // set the SR latch at the end of the CPU read. Here's where the clock alignment differences begin. :)\n                        PPU_2007_Read = true; // Start the $2007 Read state machine.\n\n                        break;\n                }\n                dataPinsAreNotFloating = true;\n\n            }\n            else\n            {\n                //mapper chip stuff, but also open bus!\n                MapperFetch(Address, Cart.MemoryMapper);\n            }\n\n            if (addressBus >= 0x4000 && addressBus <= 0x401F) // If APU registers are active, bus conflicts can occur. Or perhaps you are intentionally reading from the APU registers...\n            {\n                //addressBus \n                byte Reg = (byte)(Address & 0x1F);\n                if (Reg == 0x15)\n                {\n\n                    internalBus &= 0x20;\n                    internalBus |= (byte)(APU_Status_DMCInterrupt ? 0x80 : 0);\n                    internalBus |= (byte)(APU_Status_FrameInterrupt ? 0x40 : 0);\n                    internalBus |= (byte)((APU_DMC_BytesRemaining != 0 && APU_Status_DelayedDMC) ? 0x10 : 0); // see footnote.\n                    internalBus |= (byte)((APU_LengthCounter_Noise != 0) ? 0x08 : 0);\n                    internalBus |= (byte)((APU_LengthCounter_Triangle != 0) ? 0x04 : 0);\n                    internalBus |= (byte)((APU_LengthCounter_Pulse2 != 0) ? 0x02 : 0);\n                    internalBus |= (byte)((APU_LengthCounter_Pulse1 != 0) ? 0x01 : 0);\n\n                    Clearing_APU_FrameInterrupt = true;\n\n\n                    // footnote:\n                    // Consider the following. LDA #0, STA $4015, LDA $4015.\n                    // The APU_DMC_BytesRemaining byte isn't cleared until 3 or 4 cycles after writing 0 to $4015.\n                    // However, reading from $4015 after the needs to immediately have bit 4 cleared.\n\n                    return internalBus; // reading from $4015 can not affect the databus\n                }\n                else if (Reg == 0x16 || Reg == 0x17)\n                {\n                    byte ControllerRead = (byte)((((Reg == 0x16) ? (ControllerShiftRegister1 & 0x80) : (ControllerShiftRegister2 & 0x80)) == 0 ? 0 : 1) | (dataBus & 0xE0));\n\n                    // controller ports\n                    // grab 1 bit from the controller's shift register.\n                    // also add the upper 3 bits of the databus.\n\n                    if (Reg == 0x16)\n                    {\n                        // if there are 2 CPU cycles in a row that read from this address, the registers don't get shifted\n                        Controller1ShiftCounter = 2; // The shift register isn't shifted until this is 0, decremented in every APU PUT cycle\n                    }\n                    else\n                    {\n                        // if there are 2 CPU cycles in a row that read from this address, the registers don't get shifted\n                        Controller2ShiftCounter = 2; // The shift register isn't shifted until this is 0, decremented in every APU PUT cycle\n                    }\n\n                    APU_ControllerPortsStrobed = false; // This allows data to rapidly be streamed in through the A button if the controllers are read while strobed.\n                    if (DoOAMDMA && dataPinsAreNotFloating) // If all the databus pins are floating, then the controller bits are visible. Otherwise... not so much.\n                    {\n                        return dataBus;\n                    }\n                    dataBus = ControllerRead;\n\n                }\n            }\n\n            internalBus = dataBus;\n            return dataBus;\n        }\n        public byte ObservePPU(ushort Address)\n        {\n            // A way to view PPU data for various debugging tools.\n            if (Cart == null)\n            {\n                return 0;\n            }\n            // when reading from the PPU's Video RAM, there's a lot of mapper-specific behavior to consider.\n            Address &= 0x3FFF;\n            if (Address < 0x2000)\n            {\n                if (Cart.UsingCHRRAM)\n                {\n                    return Cart.CHRRAM[Address];\n                }\n                else\n                {\n                    //Pattern Table\n                    return Cart.MapperChip.FetchCHR(Address, true);\n                }\n            }\n            else // if the VRAM address is >= $2000, we need to consider nametable mirroring.\n            {\n                Address = PPUAddressWithMirroring(Address);\n                if (Address >= 0x3F00)\n                {\n                    // read from palette RAM.\n                    // Palette RAM only returns bits 0-5, so bits 6 and 7 are PPU open bus.\n                    return (byte)((PaletteRAM[Address & 0x1F] & 0x3F) | (PPUBus & 0xC0));\n                }\n                if (Cart.AlternativeNametableArrangement)\n                {\n                    if (Cart.MemoryMapper == 4)\n                    {\n                        if ((Address & 0x800) != 0)\n                        {\n                            // using the extra PRG VRAM.\n                            Address &= 0x7FF;\n                            return Cart.PRGVRAM[Address];\n                        }\n                    }\n                }\n                Address &= 0x7FF;\n                return VRAM[Address];\n            }\n        }\n\n\n        ushort PPUAddressWithMirroring(ushort Address)\n        {\n            // if the address is less than $2000, there is no mirroring.\n            if (Address < 0x2000)\n            {\n                return Address;\n            }\n\n            // if the vram address is pointing to the color palettes:\n            if (Address >= 0x3F00)\n            {\n                Address &= 0x3F1F;\n                if ((Address & 3) == 0)\n                {\n                    Address &= 0x3F0F;\n                }\n                return Address;\n            }\n            Address &= 0x2FFF; // $3000 through $3F00 is always mirrored down.\n\n            Address = Cart.MapperChip.MirrorNametable(Address);\n            return Address;\n        }\n\n        byte MapperObserve(ushort Address, byte Mapper)\n        {\n            Cart.MapperChip.FetchPRG(Address, true);\n            if (Cart.MapperChip.observedDataPinsAreNotFloating)\n            {\n                return Cart.MapperChip.observedDataBus;\n            }\n            return dataBus;\n        }\n\n        void MapperFetch(ushort Address, byte Mapper)\n        {\n            Cart.MapperChip.FetchPRG(Address, false);\n            dataPinsAreNotFloating = Cart.MapperChip.dataPinsAreNotFloating;\n            if (dataPinsAreNotFloating)\n            {\n                dataBus = Cart.MapperChip.dataBus;\n            }\n            return;\n        }\n\n        byte ReadOAM()\n        {\n            if ((PPU_Mask_ShowBackground || PPU_Mask_ShowSprites) && PPU_Scanline < 240)\n            {\n                return PPU_OAMBuffer;\n            }\n            return OAM[PPUOAMAddress];\n        }\n\n        bool PPU_PendingVBlank;\n\n        bool dataPinsAreNotFloating = false;   // used in controller reading + OAM DMA.\n        public bool TAS_ReadingTAS;         // if we're reading inputs from a TAS, this will be set.\n        public int TAS_InputSequenceIndex;  // which index from the TAS input log will be used for this current controller strobe?\n        public ushort[] TAS_InputLog; // controller [22222222 11111111]\n        public bool[] TAS_ResetLog; // just a list of booleans determining if we should soft-reset on this frame or not.\n        public bool ClockFiltering = false; // If set, TAS_InputSequenceIndex increments every time the controllers are strobed (or clocked, if the controller is held strobing). Otherwise, \"latch filtering\" is used, incrementing TAS_InputSequenceIndex once a frame.\n        public bool SyncFM2; // This is set if we're running an FM2 TAS, which (due to FCEUX's very incorrect timing of the first frame after power on) I need to start execution on scanline 240, and prevent the vblank flag from being set.\n        public void Store(byte Input, ushort Address)\n        {\n            // This is used whenever writing anywhere with the CPU\n            if (Address < 0x2000)\n            {\n                //guaranteed to be RAM\n\n                RAM[Address & 0x7FF] = Input;\n\n            }\n            else if (Address < 0x4000)\n            {\n                // $2000 through $3FFF writes to the PPU registers\n                StorePPURegisters(Address, Input);\n            }\n            else if (Address >= 0x4000 && Address <= 0x4015)\n            {\n                // Writing to $4000 through $4015 are APU registers\n                switch (Address)\n                {\n                    default:\n                        APU_Register[Address & 0xFF] = Input; break;\n                    case 0x4003:\n                        if (APU_Status_Pulse1)\n                        {\n                            APU_LengthCounter_ReloadValuePulse1 = APU_LengthCounterLUT[Input >> 3];\n                            APU_LengthCounter_ReloadPulse1 = true;\n                        }\n                        APU_ChannelTimer_Pulse1 |= (ushort)((Input &= 0x7) << 8);\n                        break;\n                    case 0x4007:\n                        if (APU_Status_Pulse2)\n                        {\n                            APU_LengthCounter_ReloadValuePulse2 = APU_LengthCounterLUT[Input >> 3];\n                            APU_LengthCounter_ReloadPulse2 = true;\n                        }\n                        APU_ChannelTimer_Pulse2 |= (ushort)((Input &= 0x7) << 8);\n                        break;\n                    case 0x400B:\n                        if (APU_Status_Triangle)\n                        {\n                            APU_LengthCounter_ReloadValueTriangle = APU_LengthCounterLUT[Input >> 3];\n                            APU_LengthCounter_ReloadTriangle = true;\n\n                        }\n                        APU_ChannelTimer_Triangle |= (ushort)((Input &= 0x7) << 8);\n                        break;\n                    case 0x400F:\n                        if (APU_Status_Noise)\n                        {\n                            APU_LengthCounter_ReloadValueNoise = APU_LengthCounterLUT[Input >> 3];\n                            APU_LengthCounter_ReloadNoise = true;\n                        }\n                        break;\n\n                    case 0x4010:\n                        APU_DMC_EnableIRQ = (Input & 0x80) != 0;\n                        APU_DMC_Loop = (Input & 0x40) != 0;\n                        APU_DMC_Rate = APU_DMCRateLUT[Input & 0xF];\n                        if (!APU_DMC_EnableIRQ)\n                        {\n                            APU_Status_DMCInterrupt = false;\n                            IRQ_LevelDetector = false;\n                        }\n                        break;\n\n                    case 0x4011:\n                        APU_DMC_Output = (byte)(Input & 0x7F);\n\n                        break;\n\n                    case 0x4012:\n                        APU_DMC_SampleAddress = (ushort)(0xC000 | (Input << 6));\n                        break;\n\n                    case 0x4013:\n                        APU_DMC_SampleLength = (ushort)((Input << 4) | 1);\n                        break;\n\n                    case 0x4014:    //OAM DMA\n                        DoOAMDMA = true;\n                        FirstCycleOfOAMDMA = true;\n                        DMAAddress = 0; // the starting address for the OAM DMC is always page aligned.\n                        DMAPage = Input;\n                        break;\n                    case 0x4015:    //DMC DMA (and other audio channels)\n\n                        APU_Status_DelayedDMC = (Input & 0x10) != 0;\n                        APU_Status_Noise = (Input & 0x08) != 0;\n                        APU_Status_Triangle = (Input & 0x04) != 0;\n                        APU_Status_Pulse2 = (Input & 0x02) != 0;\n                        APU_Status_Pulse1 = (Input & 0x01) != 0;\n\n                        APU_DelayedDMC4015 = (byte)(APU_PutCycle ? 3 : 4); // Enable in 1 APU cycles, or 1.5 APU cycles. (it will be decremented later this cycle, so it's really like 2 : 3.\n\n                        if (APU_Status_DelayedDMC && APU_DMC_BytesRemaining == 0)\n                        {\n                            // sets up the sample bytes_remaining and sample address.\n                            StartDMCSample();\n                            // However, the sample will only begin playing if the DMC is currently silent\n                            if (APU_Silent)\n                            {\n                                DMCDMADelay = 2; // 2 APU cycles\n                            }\n                        }\n\n                        if (!APU_Status_Noise) { APU_LengthCounter_Noise = 0; }\n                        if (!APU_Status_Triangle) { APU_LengthCounter_Triangle = 0; }\n                        if (!APU_Status_Pulse2) { APU_LengthCounter_Pulse2 = 0; }\n                        if (!APU_Status_Pulse1) { APU_LengthCounter_Pulse1 = 0; }\n                        APU_Status_DMCInterrupt = false;\n                        IRQ_LevelDetector = false;\n\n                        // Explicit abort stuff.\n                        if (!APU_Status_DelayedDMC && ((APU_ChannelTimer_DMC == 2 && !APU_PutCycle) || (APU_ChannelTimer_DMC == APU_DMC_Rate && APU_PutCycle))) // this will be the APU cycle that fires a DMC DMA\n                        {\n                            APU_DelayedDMC4015 = (byte)(APU_PutCycle ? 5 : 6); // Disable in 2.5 APU cycles, or 3 APU cycles.\n                            // basically, if the DMA has already begun, don't abort it for *this* edge case.\n                        }\n\n                        // Implicit abort stuff.\n                        if (APU_Status_DelayedDMC && ((APU_ChannelTimer_DMC == 10 && !APU_PutCycle) || (APU_ChannelTimer_DMC == 8 && APU_PutCycle)))\n                        {\n                            // okay, so the series of events is as follows:\n                            // the Load DMA will occur\n                            // regardless of the buffer being empty, there will be a 1-cycle DMA that gets aborted 2 cycles after the load DMA ends.\n                            APU_SetImplicitAbortDMC4015 = true; // This will occur in 8 (or 9) cpu cycles\n                        }\n\n                        break;\n                }\n\n            }\n            else if (Address == 0x4016)\n            {\n                if (TAS_ReadingTAS)\n                {\n                    APU_ControllerPortsStrobing = ((Input & 1) != 0);\n                }\n                APU_ControllerPortsStrobing = ((Input & 1) != 0);\n                if (!APU_ControllerPortsStrobing)\n                {\n                    APU_ControllerPortsStrobed = false;\n                }\n            }\n            else if (Address == 0x4017)\n            {\n                APU_FrameCounterMode = (Input & 0x80) != 0;\n                APU_FrameCounterInhibitIRQ = (Input & 0x40) != 0;\n                if (APU_FrameCounterMode)\n                {\n                    APU_HalfFrameClock = true;\n                    APU_QuarterFrameClock = true;\n                }\n                if (APU_FrameCounterInhibitIRQ)\n                {\n                    APU_Status_FrameInterrupt = false;\n                    IRQ_LevelDetector = false;\n                }\n                APU_FrameCounterReset = (byte)((APU_PutCycle ? 3 : 4));\n            }\n            else if (Address >= 0x4020)\n            {\n                // mapper chip specific stuff- but also open bus!\n                Cart.MapperChip.StorePRG(Address, Input);\n\n                //MapperStore(Input, Address, Cart.MemoryMapper);\n\n            }\n            else\n            {\n                // open bus!\n                // this doesn't write anywhere, but it still updates the databus!\n            }\n\n            dataBus = Input;\n\n        }\n\n        public void StorePPURegisters(ushort Addr, byte In)\n        {\n            //EmulateNMasterClockCycles(1); // wait for PPUSEL to go high\n            // Okay, I KNOW this shouldn't be commented out. TODO: figure out why the timing on this is off by one.\n\n            ushort AddrT = (ushort)((Addr & 0x2007));\n            switch (AddrT)\n            {\n                case 0x2000:\n                    // writing here updates a large amount of PPU flags\n                    PPUBus = In;\n                    for (int i = 0; i < 8; i++) { PPUBusDecay[i] = PPUBusDecayConstant; }\n                    if (PPU_RESET)\n                    {\n                        return;\n                    }\n\n                    \n                    // now that PPUSEL is high, the value of the databus is written to the PPU register.\n                    PPU_t = (ushort)((PPU_t & 0b0111001111111111) | ((dataBus & 0x3) << 10)); // This early write to the t register is the cause of the scanline bug in SMB1.\n                    PPU_EXT_Enable = (dataBus & 0x40) == 0x40;\n                    // technically this changes PPUControl_NMIEnabled here too, but it's invisible as the NMI polling has already happened and it will be re-enabled before then.\n\n                    EmulateNMasterClockCycles(2); // wait for the CPU databus to change. (that's right, it doesn't happen at the start of the write cycle!)\n                    PPUControl_NMIEnabled = (In & 0x80) != 0;\n                    PPUControlIncrementMode32 = (In & 0x4) != 0;\n                    PPU_Spritex16 = (In & 0x20) != 0;\n                    PPU_PatternSelect_Sprites = (In & 0x8) != 0;\n                    PPU_PatternSelect_Background = (In & 0x10) != 0;\n                    PPU_t = (ushort)((PPU_t & 0b0111001111111111) | ((In & 0x3) << 10)); // change which nametable to render.\n                    PPU_EXT_Enable = (In & 0x40) == 0x40;\n\n                    break;\n\n                case 0x2001:\n                    // writing here updates a large amount of PPU flags\n                    // Is the background being drawn? Are sprites being drawn? Greyscale / color emphasis?\n                    PPUBus = In;\n                    for (int i = 0; i < 8; i++) { PPUBusDecay[i] = PPUBusDecayConstant; }\n                    if (PPU_RESET)\n                    {\n                        return;\n                    }\n                    // Okay look, I *know* this hard-coded solution is jank and sloppy.\n                    // It is temporary.\n                    // I want to re-do the picture processing unit from the ground up, honestly.\n                    // In the mean time, let's go back to the hard-coded delays. I got the correct results from the tests while doing this.\n                    // And we can fix it later.\n                    /*\n                    EmulateNMasterClockCycles(1); // wait for PPUSEL to go high\n\n                    PPU_Mask_EmphasizeBlue = (dataBus & 0x80) != 0;\n                    PPU_Mask_Greyscale = (dataBus & 0x1) != 0;\n\n                    EmulateNMasterClockCycles(2); // wait for the CPU databus to change. (that's right, it doesn't happen at the start of the write cycle!)\n\n                    PPU_Mask_EmphasizeBlue = (In & 0x80) != 0;\n                    PPU_Mask_EmphasizeGreen = (In & 0x40) != 0;\n                    PPU_Mask_EmphasizeRed = (In & 0x20) != 0;\n                    PPU_Mask_Greyscale = (In & 0x1) != 0;\n\n                    EmulateNMasterClockCycles(4); // wait for PPUSEL to go low.\n\n                    PPU_WasRenderingBefore2001Write = PPU_Mask_ShowBackground || PPU_Mask_ShowSprites;\n\n                    PPU_Mask_8PxShowBackground = (In & 0x02) != 0;\n                    PPU_Mask_8PxShowSprites = (In & 0x04) != 0;\n                    PPU_Mask_ShowBackground = (In & 0x08) != 0;\n                    PPU_Mask_ShowSprites = (In & 0x10) != 0;\n\n                    PPU_Mask_ShowBackground_Instant = PPU_Mask_ShowBackground; // now that the PPU has updated, OAM evaluation will also recognize the change\n                    PPU_Mask_ShowSprites_Instant = PPU_Mask_ShowSprites;\n                    */\n\n\n                    switch (PPUClock & 3) //depending on CPU/PPU alignment, the delay could be different.\n                    {\n                        case 0:\n                            PPU_Update2001Delay = 2; PPU_Update2001EmphasisBitsDelay = 2; PPU_Update2001OAMCorruptionDelay = 2; break;\n                        case 1:\n                            PPU_Update2001Delay = 2; PPU_Update2001EmphasisBitsDelay = 1; PPU_Update2001OAMCorruptionDelay = 3; break; // PPU_Update2001EmphasisBitsDelay is actually 2, but different behavior than case 0 and 3.\n                        case 2:\n                            PPU_Update2001Delay = 3; PPU_Update2001EmphasisBitsDelay = 1; PPU_Update2001OAMCorruptionDelay = 3; break; // PPU_Update2001EmphasisBitsDelay is actually 2, but different behavior than case 0 and 3.\n                        case 3:\n                            PPU_Update2001Delay = 2; PPU_Update2001EmphasisBitsDelay = 2; PPU_Update2001OAMCorruptionDelay = 2; break;\n                    }\n                    PPU_WasRenderingBefore2001Write = PPU_Mask_ShowBackground || PPU_Mask_ShowSprites;\n                    PPU_Mask_ShowBackground_Instant = PPU_Mask_ShowBackground; // now that the PPU has updated, OAM evaluation will also recognize the change\n                    PPU_Mask_ShowSprites_Instant = PPU_Mask_ShowSprites;\n                    // TODO: Remove this hard-coded junk:\n                    bool temp_rendering = PPU_WasRenderingBefore2001Write;\n                    bool temp_renderingFromInput = ((In & 0x08) != 0) || ((In & 0x10) != 0);\n                    // disabling rendering can cause OAM corruption.\n                    if (temp_rendering && !temp_renderingFromInput)\n                    {\n                        // we are disabling rendering inside vblank\n                        if (PPU_Scanline < 241 || PPU_Scanline == 261)\n                        {\n                            PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant = true; // used in the next cycle of sprite evaluation\n                            if ((PPU_Dot & 7) < 2 && PPU_Dot <= 250)\n                            {\n                                // Palette corruption only occurs if rendering was disabled during the first 2 dots of a nametable fetch\n                                // TODO: Fiskbit has enlightened me a bit on how this is actually working:\n                                // The VRAM address muxer selects between the PAR, NT address, AT address, and v.\n                                // v isn't an explicit input; it's actually the NT input when rendering is disabled.\n                                // The AT input actually sources a lot of its bits from the NT input, and this leads to an unfortunate bug where turning rendering off during an AT fetch actually results in a brief period where you have an AT input that is sourcing from v instead of an NT address.\n                                // And the address muxer ends up using this AT input briefly right after rendering is disabled.\n                                // This is why you can get palette RAM corruption when turning rendering off during an AT fetch if v was pointing into $3C00-$3EFF, despite this clearly not being palette RAM. The AT input that is being used actually points into palette RAM because those 2 bits are forced to 1.\n                                if ((PPU_v & 0x3FFF) >= 0x3C00) // palette corruption only appears to occur when disabling rendering if the VRAM address is currently greater than 3C00\n                                {\n                                    PPU_PaletteCorruptionRenderingDisabledOutOfVBlank = true; // used in the color calculation for the next dot being drawn\n                                }\n                            }\n                        }\n                    }\n                    else if (!temp_rendering && temp_renderingFromInput)\n                    {\n                        if (PPU_Scanline < 241 || PPU_Scanline == 261)\n                        {\n                            // if re-enabling rendering outside vblank\n                            if (PPU_PendingOAMCorruption)\n                            {\n                                // If OAM corruption is going to occur\n                                if (PPUClock == 1 || PPUClock == 2)\n                                {\n                                    // if on clock alignment 1 or 2, it doesn't happen!\n                                    PPU_OAMCorruptionRenderingEnabledOutOfVBlank = true;\n                                }\n                            }\n                        }\n                    }\n\n                    // This is temp. I know it's wrong (we're not even waiting for PPUSEL here.) but I'll fix it after redoing the entire ppu or something.\n                    if (PPU_Update2001EmphasisBitsDelay == 2)\n                    {\n                        PPU_Mask_Greyscale = (dataBus & 0x01) != 0;\n                        PPU_Mask_EmphasizeBlue = (dataBus & 0x80) != 0;\n                    }\n                    else\n                    {\n                        PPU_Update2001EmphasisBitsDelay++; // it's always 2.\n                    }\n                    PPU_Mask_EmphasizeRed = (In & 0x20) != 0;\n                    PPU_Mask_EmphasizeGreen = (In & 0x40) != 0;\n\n                    PPU_Update2001Value = In;\n\n                    break;\n\n                case 0x2002: // this value is Read only.\n                    PPUBus = In;\n                    for (int i = 0; i < 8; i++) { PPUBusDecay[i] = PPUBusDecayConstant; }\n                    break;\n\n                case 0x2003:\n                    // writing here updates the OAM address\n                    PPUBus = In;\n                    for (int i = 0; i < 8; i++) { PPUBusDecay[i] = PPUBusDecayConstant; }\n                    PPUOAMAddress = PPUBus;\n                    break;\n\n                case 0x2004:\n                    // writing here updates the OAM byte at the current OAM address\n                    PPUBus = In;\n                    for (int i = 0; i < 8; i++) { PPUBusDecay[i] = PPUBusDecayConstant; }\n                    if (((PPU_Scanline >= 240 && PPU_Scanline < 261) && (PPU_Mask_ShowBackground || PPU_Mask_ShowSprites)) || (!PPU_Mask_ShowBackground && !PPU_Mask_ShowSprites))\n                    {\n                        if ((PPUOAMAddress & 3) == 2)\n                        {\n                            In &= 0xE3;\n                        }\n                        OAM[PPUOAMAddress] = In;\n                        PPUOAMAddress++;\n                    }\n                    else\n                    {\n                        PPUOAMAddress += 4;\n                        PPUOAMAddress &= 0xFC;\n\n                    }\n                    break;\n\n                case 0x2005:\n                    // writing here updates the X and Y scroll\n                    PPUBus = In;\n                    for (int i = 0; i < 8; i++) { PPUBusDecay[i] = PPUBusDecayConstant; }\n                    if (PPU_RESET)\n                    {\n                        return;\n                    }\n                    switch (PPUClock & 3) //depending on CPU/PPU alignment, the delay could be different.\n                    {\n                        case 0: PPU_Update2005Delay = 1; break;\n                        case 1: PPU_Update2005Delay = 1; break;\n                        case 2: PPU_Update2005Delay = 2; break;\n                        case 3: PPU_Update2005Delay = 1; break;\n                    }\n                    PPU_Update2005Value = In;\n                    // There's a slight delay before the PPU updates the scroll with the correct values.\n                    // In the meantime, it uses the value from the databus.\n                    if (!PPUAddrLatch)\n                    {\n                        PPU_FineXScroll = (byte)(dataBus & 7);\n                        PPU_t = (ushort)((PPU_t & 0b0111111111100000) | (dataBus >> 3));\n                    }\n                    else\n                    {\n                        PPU_t = (ushort)((PPU_t & 0b0000110000011111) | (((dataBus & 0xF8) << 2) | ((dataBus & 7) << 12)));\n                    }\n                    break;\n\n                case 0x2006:\n                    // writing here updates the PPU's read/write address.\n                    PPUBus = In;\n                    for (int i = 0; i < 8; i++) { PPUBusDecay[i] = PPUBusDecayConstant; }\n                    if (PPU_RESET)\n                    {\n                        return;\n                    }\n\n                    if (!PPUAddrLatch)\n                    {\n                        PPU_t = (ushort)((PPU_t & 0b000000011111111) | ((In & 0x3F) << 8));\n\n                    }\n                    else\n                    {\n                        PPU_t = (ushort)((PPU_t & 0b0111111100000000) | (In));\n                        PPU_Update2006Value = PPU_t;\n                        PPU_Update2006Value_Temp = PPU_v;\n                        switch (PPUClock & 3) //depending on CPU/PPU alignment, the delay could be different.\n                        {\n                            case 0: PPU_Update2006Delay = 4; break;\n                            case 1: PPU_Update2006Delay = 4; break;\n                            case 2: PPU_Update2006Delay = 5; break;\n                            case 3: PPU_Update2006Delay = 4; break;\n                        }\n                    }\n                    PPUAddrLatch = !PPUAddrLatch;\n\n                    break;\n\n                case 0x2007:\n                    // writing here updates the byte at the current read/write address\n                    PPUBus = In;\n                    PPU_2007_WriteData = PPUBus;\n                    for (int i = 0; i < 8; i++) { PPUBusDecay[i] = PPUBusDecayConstant; }\n                    EmulateNMasterClockCycles(7); // wait for PPUSEL to go low\n                    PPU_2007_Write = true;\n                    PPU_2007_Write_SR = true; // set the SR latch at the end of the CPU write. Here's where the clock alignment differences begin. :)\n                    break;\n                // and that's it for the ppu registers!\n\n                default: break; //should never happen\n            }\n\n\n        }\n\n        void StorePPUData(ushort Address, byte In)\n        {\n            // writing to the PPU's VRAM.\n            // first, check if the address has any mirroring going on:\n            Address = PPUAddressWithMirroring(Address);\n            if (Address < 0x2000) // if this is pointing to CHR RAM\n            {\n                Cart.CHRRAM[Address] = In;\n            }\n            else if (Address >= 0x3F00)\n            {\n                PaletteRAM[Address & 0x1F] = In;\n            }\n            else // if this is not pointing to CHR RAM or palettes\n            {\n                if (Cart.AlternativeNametableArrangement)\n                {\n                    if (Cart.MemoryMapper == 4)\n                    {\n                        if ((Address & 0x800) != 0)\n                        {\n                            // using the extra PRG VRAM.\n                            Cart.PRGVRAM[Address & 0x7FF] = In;\n                            return;\n                        }\n                    }\n                }\n                VRAM[Address & 0x7FF] = In;\n\n            }\n        }\n\n        void StartDMCSample()\n        {\n            // This runs when writing to $4015, or if a DPCM sample is looping and needs to restart.\n            APU_DMC_AddressCounter = APU_DMC_SampleAddress;\n            APU_DMC_BytesRemaining = APU_DMC_SampleLength;\n        }\n\n\n        #region GetAddressFunctions\n\n        // these functions are used inside the giant opcode switch statement.\n\n        void GetImmediate()\n        {\n            // Fetch the value at the program counter, store it in the DataLatch, and increment the Program Counter.\n            dl = Fetch(programCounter);\n            programCounter++;\n            addressBus = programCounter;\n        }\n\n        void GetAddressAbsolute()\n        {\n            // Fetch the value at the PC, and write to either the High byte or Low byte of the 16 bit address bus. Also increment the Program Counter.\n            if (operationCycle == 1)\n            {\n                // fetch address low\n                dl = Fetch(programCounter);\n            }\n            else\n            {\n                // fetch address high\n                addressBus = (ushort)(dl | (Fetch(programCounter) << 8));\n            }\n            programCounter++;\n        }\n\n        void GetAddressZeroPage()\n        {\n            // Fetch the value at the PC, and this 8 bit value replaces the contents of the 16 bit address bus.\n            addressBus = Fetch(programCounter);\n            programCounter++;\n        }\n\n        void GetAddressIndOffX()\n        {\n            // Fetch the value from the PC, then using that value as an 8-bit address on the zero page, add the X register, then set the High byte and Low byte of the Address Bus from there.\n            switch (operationCycle)\n            {\n                case 1: // fetch pointer address\n                    addressBus = Fetch(programCounter);\n                    programCounter++;\n                    break;\n                case 2: // Add X\n                    // dummy read\n                    Fetch(addressBus);\n                    addressBus = (byte)(addressBus + X);\n                    break;\n                case 3: // fetch address low\n                    dl = Fetch((byte)(addressBus));\n                    break;\n                case 4: // fetch address high\n                    addressBus = (ushort)(dl | (Fetch((byte)(addressBus + 1)) << 8));\n                    break;\n            }\n        }\n\n        void GetAddressIndOffY(bool TakeExtraCycleOnlyIfPageBoundaryCrossed)\n        {\n            // Some instructions will always take 4 cycles to determine the address, and others will normally take 3, but take the extra cycle if a page boundary was crossed.\n\n            // either way, the general gist of this function is:\n            // Fetch the value from the PC. use that 8 bit location on the zero page to fetch the High and Low byte of the new Address Bus location, then add Y to that.\n            if (TakeExtraCycleOnlyIfPageBoundaryCrossed)\n            {\n                switch (operationCycle)\n                {\n                    case 1: // fetch pointer address\n                        addressBus = Fetch(programCounter);\n                        programCounter++;\n                        break;\n                    case 2: // fetch address low\n                        dl = Fetch((byte)(addressBus));\n                        break;\n                    case 3: // fetch address high, add Y to low byte\n                        addressBus = (ushort)(dl | (Fetch((byte)(addressBus + 1)) << 8));\n                        temporaryAddress = addressBus;\n                        H = (byte)(addressBus >> 8);\n                        if (((temporaryAddress + Y) & 0xFF00) == (temporaryAddress & 0xFF00))\n                        {\n                            operationCycle++; //skip next cycle\n                        }\n                        addressBus = (ushort)((addressBus & 0xFF00) | ((addressBus + Y) & 0xFF));\n                        break;\n                    case 4: // increment high byte\n                        dl = Fetch(addressBus); // dummy read\n                        H = (byte)(addressBus >> 8);\n                        H++; // This is incremented.\n                        addressBus += 0x100;\n                        break;\n                }\n            }\n            else\n            {\n                switch (operationCycle)\n                {\n                    case 1: // fetch pointer address\n                        addressBus = Fetch(programCounter);\n                        programCounter++;\n                        break;\n                    case 2: // fetch address low\n                        dl = Fetch((byte)(addressBus));\n                        break;\n                    case 3: // fetch address high, add Y to low byte\n                        addressBus = (ushort)(dl | (Fetch((byte)(addressBus + 1)) << 8));\n                        temporaryAddress = addressBus;\n                        addressBus = (ushort)((addressBus & 0xFF00) | ((addressBus + Y) & 0xFF));\n                        break;\n                    case 4: // increment high byte\n                        dl = Fetch(addressBus); // dummy read\n                        H = (byte)(addressBus >> 8);\n                        H++; // This is incremented.\n                        if (((temporaryAddress + Y) & 0xFF00) != (temporaryAddress & 0xFF00))\n                        {\n                            addressBus += 0x100; // really, this would just replace the high byte with H, but this is less computationally expensive\n                        }\n                        break;\n                }\n            }\n\n        }\n\n        void GetAddressZPOffX()\n        {\n            // Fetch the value from the PC, then add X to that.\n            if (operationCycle == 1)\n            {\n                // fetch address\n                addressBus = Fetch(programCounter);\n                programCounter++;\n            }\n            else\n            {\n                // dummy read, and add X\n                dl = Fetch(addressBus);\n                addressBus = (byte)(addressBus + X);\n            }\n        }\n\n        void GetAddressZPOffY()\n        {\n            // Fetch the value from the PC, then add Y to that.\n            if (operationCycle == 1)\n            {\n                // fetch address\n                addressBus = Fetch(programCounter);\n                programCounter++;\n            }\n            else\n            {\n                // dummy read, and add Y\n                dl = Fetch(addressBus);\n                addressBus = (byte)(addressBus + Y);\n            }\n        }\n\n        void GetAddressAbsOffX(bool TakeExtraCycleIfPageBoundaryCrossed)\n        {\n            // Some instructions will always take 4 cycles to determine the address, and others will normally take 3, but take the extra cycle if a page boundary was crossed.\n\n            // Fetch the High and Low byte values from the byte at the PC, then add X.\n            if (TakeExtraCycleIfPageBoundaryCrossed)\n            {\n                switch (operationCycle)\n                {\n                    case 1: // fetch address low\n                        dl = Fetch(programCounter);\n                        programCounter++;\n\n                        break;\n                    case 2: // fetch address high, add Y to low byte\n                        addressBus = (ushort)(dl | Fetch(programCounter) << 8);\n                        temporaryAddress = addressBus;\n                        H = (byte)(addressBus >> 8);\n\n                        if (((temporaryAddress + X) & 0xFF00) == (temporaryAddress & 0xFF00))\n                        {\n                            operationCycle++; //skip next cycle\n                            FixHighByte = false;\n                        }\n                        else\n                        {\n                            FixHighByte = true;\n                        }\n\n                        addressBus = (ushort)((addressBus & 0xFF00) | ((addressBus + X) & 0xFF));\n                        programCounter++;\n\n                        break;\n                    case 3: // increment high byte\n                        dl = Fetch(addressBus);\n                        H = (byte)(addressBus >> 8);\n                        H++;\n                        if (FixHighByte)\n                        {\n                            addressBus += 0x100;\n                        }\n                        break;\n                    case 4: // dummy read\n                        dl = Fetch(addressBus); // read into pd\n                        break;\n                }\n            }\n            else\n            {\n                switch (operationCycle)\n                {\n                    case 1: // fetch address low\n                        dl = Fetch(programCounter);\n                        programCounter++;\n\n                        break;\n                    case 2: // fetch address high, add Y to low byte\n                        addressBus = (ushort)(dl | Fetch(programCounter) << 8);\n                        temporaryAddress = addressBus;\n                        addressBus = (ushort)((addressBus & 0xFF00) | ((addressBus + X) & 0xFF));\n                        programCounter++;\n\n                        break;\n                    case 3: // fix high byte if applicable\n                        dl = Fetch(addressBus); // read into pd\n                        H = (byte)(addressBus >> 8);\n                        H++;\n                        if (((temporaryAddress + X) & 0xFF00) != (temporaryAddress & 0xFF00))\n                        {\n                            addressBus += 0x100;\n                        }\n                        break;\n                    case 4: // dummy read\n                        dl = Fetch(addressBus); // read into pd\n                        break;\n                }\n            }\n        }\n        bool FixHighByte = false;\n        void GetAddressAbsOffY(bool TakeExtraCycleIfPageBoundaryCrossed)\n        {\n            // Some instructions will always take 4 cycles to determine the address, and others will normally take 3, but take the extra cycle if a page boundary was crossed.\n\n            // Fetch the High and Low byte values from the byte at the PC, then add Y.\n            if (TakeExtraCycleIfPageBoundaryCrossed)\n            {\n                switch (operationCycle)\n                {\n                    case 1: // fetch address low\n                        dl = Fetch(programCounter);\n                        programCounter++;\n\n                        break;\n                    case 2: // fetch address high, add Y to low byte\n                        addressBus = (ushort)(dl | Fetch(programCounter) << 8);\n                        temporaryAddress = addressBus;\n                        H = (byte)(addressBus >> 8);\n\n                        if (((temporaryAddress + Y) & 0xFF00) == (temporaryAddress & 0xFF00))\n                        {\n                            operationCycle++; //skip next cycle\n                            FixHighByte = false;\n                        }\n                        else\n                        {\n                            FixHighByte = true;\n                        }\n\n                        addressBus = (ushort)((addressBus & 0xFF00) | ((addressBus + Y) & 0xFF));\n                        programCounter++;\n\n                        break;\n                    case 3: // increment high byte\n                        dl = Fetch(addressBus);\n                        H = (byte)(addressBus >> 8);\n                        H++;\n                        if (FixHighByte)\n                        {\n                            addressBus += 0x100;\n                        }\n                        break;\n                    case 4: // dummy read\n                        dl = Fetch(addressBus); // read into databus\n                        break;\n                }\n            }\n            else\n            {\n                switch (operationCycle)\n                {\n                    case 1: // fetch address low\n                        dl = Fetch(programCounter);\n                        programCounter++;\n\n                        break;\n                    case 2: // fetch address high, add Y to low byte\n                        addressBus = (ushort)(dl | Fetch(programCounter) << 8);\n                        temporaryAddress = addressBus;\n                        addressBus = (ushort)((addressBus & 0xFF00) | ((addressBus + Y) & 0xFF));\n                        programCounter++;\n\n                        break;\n                    case 3: // fix high byte if applicable\n                        dl = Fetch(addressBus); // read into pd\n                        H = (byte)(addressBus >> 8);\n                        H++;\n                        if (((temporaryAddress + Y) & 0xFF00) != (temporaryAddress & 0xFF00))\n                        {\n                            addressBus += 0x100;\n                        }\n                        break;\n                    case 4: // dummy read\n                        dl = Fetch(addressBus); // read into pd\n                        break;\n                }\n            }\n        }\n        #endregion\n\n        #region OpFunctions\n\n        // This is not every instruction!!!\n        // These are just the ones that have frequently repeated logic.\n        // Instructions like STA just simply `Store(A, Address);`, which doesn't need a jump somewhere to do that.\n        // Many undocumented opcodes have unique behavior that is also just handled in the switch statement, instead of jumping to a unique function.\n\n        void Op_ORA(byte Input)\n        {\n            // Bitwise OR A with some value\n            A |= Input;\n            flag_Negative = A >= 0x80; // if bit 7 of the result is set\n            flag_Zero = A == 0x00;     // if all bits are cleared\n        }\n\n        void Op_ASL(byte Input, ushort Address)\n        {\n            // Arithmetic shift left.\n            flag_Carry = Input >= 0x80;    // If bit 7 was set before the shift\n            Input <<= 1;\n            Store(Input, Address);         // store the result at the target address\n            flag_Negative = Input >= 0x80; // if bit 7 of the result is set\n            flag_Zero = Input == 0x00;     // if all bits are cleared\n        }\n\n        void Op_ASL_A()\n        {\n            // Arithmetic shift left the Accumulator\n            flag_Carry = A >= 0x80;    // If bit 7 was set before the shift\n            A <<= 1;\n            flag_Negative = A >= 0x80; // if bit 7 of the result is set\n            flag_Zero = A == 0x00;     // if all bits are cleared\n        }\n\n        void Op_SLO(byte Input, ushort Address)\n        {\n            // Undocumented Opcode: equivalent to ASL + ORA\n            Op_ASL(Input, Address);\n            Op_ORA(dataBus);\n        }\n\n        void Op_AND(byte Input)\n        {\n            // Bitwise AND with A\n            A &= Input;\n            flag_Negative = A >= 0x80; // if bit 7 of the result is set\n            flag_Zero = A == 0x00;     // if all bits are cleared\n        }\n\n        void Op_ROL(byte Input, ushort Address)\n        {\n            // Rotate Left\n            bool Futureflag_Carry = Input >= 0x80;\n            Input <<= 1;\n            if (flag_Carry)\n            {\n                Input |= 1; // Put the old carry flag value into bit 0\n            }\n            Store(Input, Address);         // store the result at the target address\n            flag_Carry = Futureflag_Carry; // if bit 7 of the initial value was set\n            flag_Negative = Input >= 0x80; // if bit 7 of the result is set\n            flag_Zero = Input == 0x00;     // if all bits are cleared\n        }\n\n        void Op_ROL_A()\n        {\n            // Rotate Left the Accumulator\n            bool Futureflag_Carry = A >= 0x80;\n            A <<= 1;\n            if (flag_Carry)\n            {\n                A |= 1; // Put the old carry flag value into bit 0\n            }\n            flag_Carry = Futureflag_Carry; // if bit 7 of the initial value was set\n            flag_Negative = A >= 0x80;     // if bit 7 of the result is set\n            flag_Zero = A == 0x00;         // if all bits are cleared\n        }\n\n        void Op_RLA(byte Input, ushort Address)\n        {\n            // Undocumented Opcode: equivalent to ROL + AND\n            Op_ROL(Input, Address);\n            Op_AND(dataBus);\n        }\n\n        void Op_EOR(byte Input)\n        {\n            // Bitwise Exclusive OR A\n            A ^= Input;\n            flag_Negative = A >= 0x80; // if bit 7 of the result is set\n            flag_Zero = A == 0x00;     // if all bits are cleared\n        }\n\n        void Op_LSR(byte Input, ushort Address)\n        {\n            // Logical Shift Right\n            flag_Carry = (Input & 1) == 1; // If bit 0 of the initial value is set\n            Input >>= 1;\n            Store(Input, Address);         // store the result at the target address\n            flag_Negative = Input >= 0x80; // if bit 7 of the result is set\n            flag_Zero = Input == 0x00;     // if all bits are cleared\n        }\n\n        void Op_LSR_A()\n        {\n            // Logical Shift Right the Accumulator\n            flag_Carry = (A & 1) == 1; // If bit 0 of the initial value is set\n            A >>= 1;\n            flag_Negative = A >= 0x80; // if bit 7 of the result is set\n            flag_Zero = A == 0x00;     // if all bits are cleared\n        }\n\n        void Op_SRE(byte Input, ushort Address)\n        {\n            // Undocumented Opcode: equivalent to LSR + EOR\n            Op_LSR(Input, Address);\n            Op_EOR(dataBus);\n        }\n\n        void Op_ADC(byte Input)\n        {\n            // Add with Carry\n            int Intput = Input + A + (flag_Carry ? 1 : 0);\n            flag_Overflow = (~(A ^ Input) & (A ^ Intput) & 0x80) != 0;\n            flag_Carry = Intput > 0xFF;\n            A = (byte)Intput;\n            flag_Negative = A >= 0x80; // if bit 7 of the result is set\n            flag_Zero = A == 0x00;     // if all bits are cleared\n        }\n\n        void Op_ROR(byte Input, ushort Address)\n        {\n            // Rotate Right\n            bool FutureFlag_Carry = (Input & 1) == 1; // if bit 0 was set before the shift\n            Input >>= 1;\n            if (flag_Carry)\n            {\n                Input |= 0x80;  // put the old carry flag into bit 7\n            }\n            Store(Input, Address);\n            flag_Carry = FutureFlag_Carry; // if bit 0 was set before the shift\n            flag_Negative = Input >= 0x80; // if bit 7 of the result is set\n            flag_Zero = Input == 0x00;     // if all bits are cleared\n        }\n\n        void Op_ROR_A()\n        {\n            bool FutureFlag_Carry = (A & 1) == 1;\n            A >>= 1;\n            if (flag_Carry)\n            {\n                A |= 0x80;  // put the old carry flag into bit 7\n            }\n            flag_Carry = FutureFlag_Carry; // if bit 0 was set before the shift\n            flag_Negative = A >= 0x80;     // if bit 7 of the result is set\n            flag_Zero = A == 0x00;         // if all bits are cleared\n        }\n\n        void Op_RRA(byte Input, ushort Address)\n        {\n            // Undocumented Opcode: equivalent to ROR + ADC\n            Op_ROR(Input, Address);\n            Op_ADC(dataBus);\n        }\n\n        void Op_CMP(byte Input)\n        {\n            // Compare A\n            flag_Zero = A == Input; // if A is equal to the value being compared\n            flag_Carry = A >= Input;// if A is greater than the value being compared\n            flag_Negative = ((byte)(A - Input) >= 0x80); // if A - the value being compared would leave bit 7 set\n        }\n\n        void Op_CPY(byte Input)\n        {\n            // Compare Y\n            flag_Zero = Y == Input; // if Y is equal to the value being compared\n            flag_Carry = Y >= Input;// if Y is greater than the value being compared\n            flag_Negative = ((byte)(Y - Input) >= 0x80); // if Y - the value being compared would leave bit 7 set\n        }\n\n        void Op_CPX(byte Input)\n        {\n            // Compare X\n            flag_Zero = X == Input; // if X is equal to the value being compared\n            flag_Carry = X >= Input;// if X is greater than the value being compared\n            flag_Negative = ((byte)(X - Input) >= 0x80); // if X - the value being compared would leave bit 7 set\n        }\n\n        void Op_SBC(byte Input)\n        {\n            // Subtract with Carry\n            int Intput = A - Input;\n            if (!flag_Carry)\n            {\n                Intput -= 1;\n            }\n            flag_Overflow = ((A ^ Input) & (A ^ Intput) & 0x80) != 0;\n            flag_Carry = Intput >= 0;\n            A = (byte)Intput;\n            flag_Negative = A >= 0x80; // if bit 7 of the result is set\n            flag_Zero = A == 0x00;     // if all bits are cleared\n        }\n\n        void Op_INC(ushort Address)\n        {\n            // Increment\n            dl++;   // The value read is currently stored in the PreDecode register\n            flag_Zero = dl == 0;        // if all bits are cleared\n            flag_Negative = dl >= 0x80; // if bit 7 of the result is set\n            Store(dl, Address);\n\n        }\n\n        void Op_DEC(ushort Address)\n        {\n            // Decrement\n            dl--;  // The value read is currently stored in the PreDecode register\n            flag_Zero = dl == 0;        // if all bits are cleared\n            flag_Negative = dl >= 0x80; // if bit 7 of the result is set\n            Store(dl, Address);\n\n        }\n\n\n        #endregion\n\n        // this is the tracelogger.\n        // I call this function during the first cycle of every instruction.\n\n        public ushort DebugRange_Low = 0x0000;\n        public ushort DebugRange_High = 0xFFFF;\n        public bool OnlyDebugInRange = false;\n        void Debug()\n        {\n            if (OnlyDebugInRange)\n            {\n                if (programCounter < DebugRange_Low || programCounter > DebugRange_High)\n                {\n                    return;\n                }\n            }\n\n            string addr = programCounter.ToString(\"X4\");\n            string bytes = \"\";\n            int b = 0;\n            while (b < Documentation.OpDocs[opCode].length)\n            {\n                string t = Observe((ushort)(programCounter + b)).ToString(\"X\");\n                if (t.Length == 1) { t = \"0\" + t; }\n                t += \" \";\n                bytes = bytes + t;\n                b++;\n            }\n\n            if (bytes.Length < 7)\n            {\n                bytes += \"\\t\";\n            }\n\n            string sA = A.ToString(\"X2\");\n            string sX = X.ToString(\"X2\");\n            string sY = Y.ToString(\"X2\");\n            string sS = stackPointer.ToString(\"X2\");\n\n            string Flags = \"\";\n            Flags += flag_Negative ? \"N\" : \"n\";\n            Flags += flag_Overflow ? \"V\" : \"v\";\n            Flags += \"--\";\n            Flags += flag_Decimal ? \"D\" : \"d\";\n            Flags += flag_Interrupt ? \"I\" : \"i\";\n            Flags += flag_Zero ? \"Z\" : \"z\";\n            Flags += flag_Carry ? \"C\" : \"c\";\n\n\n            if (DebugLog == null)\n            {\n                DebugLog = new StringBuilder();\n            }\n\n            string instruction = Documentation.OpDocs[opCode].mnemonic + \" \";\n\n            if (opCode == 0)\n            {\n                if (DoReset)\n                {\n                    instruction = \"RESET\";\n                    bytes = \"--\\t\";\n                }\n                else if (DoNMI)\n                {\n                    instruction = \"NMI\";\n                    bytes = \"--\\t\";\n\n                }\n                else if (DoIRQ)\n                {\n                    instruction = \"IRQ\";\n                    bytes = \"--\\t\";\n\n                }\n            }\n\n            ushort Target = 0;\n\n            switch (Documentation.OpDocs[opCode].mode)\n            {\n                case \"i\": //implied\n                    break;\n                case \"d\": //zp\n                    instruction += \"<$\" + Observe((ushort)(programCounter + 1)).ToString(\"X2\"); Target = Observe((ushort)(programCounter + 1)); break;\n                case \"a\": //abs\n                    instruction += \"$\" + Observe((ushort)(programCounter + 2)).ToString(\"X2\") + Observe((ushort)(programCounter + 1)).ToString(\"X2\"); Target = (ushort)((Observe((ushort)(programCounter + 2)) << 8) | Observe((ushort)(programCounter + 1))); break;\n                case \"r\": //relative\n                    instruction += \"$\" + ((ushort)(programCounter + (sbyte)Observe((ushort)(programCounter + 1))) + 2).ToString(\"X4\"); Target = (ushort)((ushort)(programCounter + (sbyte)Observe((ushort)(programCounter + 1))) + 2); break;\n                case \"#v\": //imm\n                    instruction += \"#\" + Observe((ushort)(programCounter + 1)).ToString(\"X2\"); Target = Observe((ushort)(programCounter + 1)); break;\n                case \"A\": //A\n                    instruction += \"A\"; break;\n                case \"(a)\": //(ind)\n                    instruction += \"($\" + Observe((ushort)(programCounter + 2)).ToString(\"X2\") + Observe((ushort)(programCounter + 1)).ToString(\"X2\") + \") -> $\" + (Observe((ushort)(Observe((ushort)(programCounter + 1)) + Observe((ushort)(programCounter + 2)) * 0x100)) + Observe((ushort)((Observe((ushort)(programCounter + 1)) + Observe((ushort)(programCounter + 2)) * 0x100) + 1)) * 0x100).ToString(\"X4\"); Target = (ushort)(Observe((ushort)(Observe((ushort)(programCounter + 1)) + Observe((ushort)(programCounter + 2)) * 0x100)) + Observe((ushort)((Observe((ushort)(programCounter + 1)) + Observe((ushort)(programCounter + 2)) * 0x100) + 1)) * 0x100); break;\n                case \"d,x\": //zp, x\n                    instruction += \"<$\" + Observe((ushort)(programCounter + 1)).ToString(\"X2\") + \", X -> $\" + (Observe((ushort)(programCounter + 1)) + X).ToString(\"X2\"); Target = (ushort)(Observe((ushort)(programCounter + 1)) + X); break;\n                case \"d,y\": //zp, y\n                    instruction += \"<$\" + Observe((ushort)(programCounter + 1)).ToString(\"X2\") + \", Y -> $\" + (Observe((ushort)(programCounter + 1)) + Y).ToString(\"X2\"); Target = (ushort)(Observe((ushort)(programCounter + 1)) + Y); break;\n                case \"a,x\": //abs, x\n                    instruction += \"$\" + Observe((ushort)(programCounter + 2)).ToString(\"X2\") + Observe((ushort)(programCounter + 1)).ToString(\"X2\") + \", X -> $\" + ((ushort)(Observe((ushort)(programCounter + 1)) + Observe((ushort)(programCounter + 2)) * 0x100 + X)).ToString(\"X4\"); Target = (ushort)(Observe((ushort)(programCounter + 1)) + Observe((ushort)(programCounter + 2)) * 0x100 + X); break;\n                case \"a,y\": //abs, Y\n                    instruction += \"$\" + Observe((ushort)(programCounter + 2)).ToString(\"X2\") + Observe((ushort)(programCounter + 1)).ToString(\"X2\") + \", Y -> $\" + ((ushort)(Observe((ushort)(programCounter + 1)) + Observe((ushort)(programCounter + 2)) * 0x100 + Y)).ToString(\"X4\"); Target = (ushort)(Observe((ushort)(programCounter + 1)) + Observe((ushort)(programCounter + 2)) * 0x100 + Y); break;\n                case \"(d),y\": //(zp), Y\n                    instruction += \"($00\" + Observe((ushort)(programCounter + 1)).ToString(\"X2\") + \"), Y -> $\" + ((ushort)(Observe(Observe((ushort)(programCounter + 1))) + Observe((ushort)((byte)(Observe((ushort)(programCounter + 1)) + 1) + (ushort)((Observe((ushort)(programCounter + 1)) & 0xFF00)))) * 0x100) + Y).ToString(\"X4\"); Target = (ushort)((ushort)(Observe(Observe((ushort)(programCounter + 1))) + Observe((ushort)((byte)(Observe((ushort)(programCounter + 1)) + 1) + (ushort)((Observe((ushort)(programCounter + 1)) & 0xFF00)))) * 0x100) + Y); break;\n                case \"(d,x)\": //(zp, X)\n                    instruction += \"($00\" + Observe((ushort)(programCounter + 1)).ToString(\"X2\") + \", X) -> $\" + (Observe((byte)(Observe((ushort)(programCounter + 1)) + X)) + Observe((ushort)((byte)((byte)(Observe((ushort)(programCounter + 1)) + X) + 1) + (ushort)(((byte)(Observe((ushort)(programCounter + 1)) + X) & 0xFF00)))) * 0x100).ToString(\"X4\"); Target = (ushort)(Observe((byte)(Observe((ushort)(programCounter + 1)) + X)) + Observe((ushort)((byte)((byte)(Observe((ushort)(programCounter + 1)) + X) + 1) + (ushort)(((byte)(Observe((ushort)(programCounter + 1)) + X) & 0xFF00)))) * 0x100); break;\n\n            }\n\n            if (Target == 0x2007)\n            {\n                instruction += \" | PPU[$\" + PPU_v.ToString(\"X4\") + \"]\";\n            }\n\n\n\n            if (instruction.Length < 8)\n            {\n                instruction += \"\\t\";\n            }\n            if (instruction.Length < 17)\n            {\n                instruction += \"\\t\";\n            }\n\n            int PPUCycle = 0;\n            String PPUPos = \"(\" + PPU_Scanline + \", \" + PPU_Dot + \")\";\n\n\n\n            if (totalCycles < 27395)\n            {\n                PPUCycle = PPU_Scanline * 341 + PPU_Dot;\n            }\n            else\n            {\n                if (PPU_Scanline >= 241)\n                {\n                    PPUCycle = (PPU_Scanline - 241) * 341 + PPU_Dot;\n                }\n                else\n                {\n                    PPUCycle = (PPU_Scanline + 21) * 341 + PPU_Dot;\n                }\n            }\n\n            if ((PPUPos.Length + PPUCycle.ToString().Length + 1) < 13)\n            {\n                PPUPos += \"\\t\";\n            }\n\n            string LogLine = \"$\" + addr + \"\\t\" + bytes + \"\\t\" + instruction + \"\\tA:\" + sA + \"\\tX:\" + sX + \"\\tY:\" + sY + \"\\tSP:\" + sS + \"\\t\" + Flags + \"\\tCycle: \" + totalCycles;\n\n            bool LogExtra = true;\n            if (LogExtra)\n            {\n                string TempLine_APU_Full = LogLine + \"\\t\" + \"DMC :: S_Addr: $\" + APU_DMC_SampleAddress.ToString(\"X4\") + \"\\t S_Length:\" + APU_DMC_SampleLength.ToString() + \"\\t AddrCounter: $\" + APU_DMC_AddressCounter.ToString(\"X4\") + \"\\t BytesLeft:\" + APU_DMC_BytesRemaining.ToString() + \"\\t Shifter:\" + APU_DMC_Shifter.ToString() + \":\" + APU_DMC_ShifterBitsRemaining.ToString() + \"\\tDMC_Timer:\" + (APU_PutCycle ? APU_ChannelTimer_DMC : (APU_ChannelTimer_DMC - 1)).ToString();\n\n\n                string TempLine_APUFrameCounter_IRQs = LogLine + \" \\t$4015: \" + Observe(0x4015).ToString(\"X2\") + \"\\t APU_FrameCounter: \" + APU_Framecounter.ToString() + \" \\tEvenCycle = : \" + APU_PutCycle + \" \\tDoIRQ = \" + DoIRQ;\n\n\n                string TempLine_PPU = LogLine + \"\\t$2000:\" + Observe(0x2000).ToString(\"X2\") + \"\\t$2001:\" + Observe(0x2001).ToString(\"X2\") + \"\\t$2002:\" + Observe(0x2002).ToString(\"X2\") + \"\\tR/W Addr:\" + PPU_v.ToString(\"X4\") + \"\\tPPUAddrLatch:\" + PPUAddrLatch + \"\\tPPU AddressBus: \" + PPU_AddressBus.ToString(\"X4\");\n                string TempLine_PPU2 = LogLine + \"\\tVRAMAddress:\" + PPU_v.ToString(\"X4\") + \"\\tPPUReadBuffer:\" + PPU_ReadBuffer.ToString(\"X2\");\n                string TempLine_PPU3 = LogLine + \"\\tPPU_Coords (\" + PPU_Scanline + \", \" + PPU_Dot + \")\\todd:\" + PPU_OddFrame.ToString() + \"\\tv: \" + PPU_v.ToString(\"X4\");\n\n                //string TempLine_MMC3IRQ = LogLine + \"\\tPPU_Coords (\" + PPU_Scanline + \", \" + PPU_Dot + \")\\tIRQTimer:\" + Cart.Mapper_4_IRQCounter + \"\\tIRQLatch: \" + Cart.Mapper_4_IRQLatch + \"\\tIRQEnabled: \" + Cart.Mapper_4_EnableIRQ + \"\\tDoIRQ: \" + DoIRQ + \"\\tPPU_ADDR_Prev: \" + (PPU_A12_Prev ? \"1\" : \"0\");\n\n\n                DebugLog.AppendLine(TempLine_PPU3);\n            }\n            else\n            {\n                DebugLog.AppendLine(LogLine);\n            }\n\n\n        }\n\n        void Debug_PPU()\n        {\n            string dotColor = \"\";\n            if (PPU_ShowScreenBorders || (PPU_Scanline < 240 && PPU_Dot <= 256 && PPU_Dot > 0))\n            {\n                dotColor = \"COLOR: \" + DotColor.ToString(\"X2\") + \"\\t\";\n            }\n            string MMC3 = \"\";\n            string Addr = \"Address: \" + PPU_AddressBus.ToString(\"X4\") + \"\\t\";\n            string Octal = \"OctalLatch: \" + PPU_OctalLatch.ToString(\"X2\") + \"\\t\";\n            string enabled = \"[\" + (PPU_Mask_ShowSprites ? \"S\" : \"-\") + (PPU_Mask_ShowBackground ? \"B\" : \"-\") + \"]\\t\";\n            string ALE = \"ALE: \" + (PPU_ALE?\"1\":\"0\") + \"\\t\";\n            string RD = \"RD: \" + (PPU_READ ? \"1\" : \"0\") + \"\\t\";\n            string BSR_Lo = \"BSRL: \" + Convert.ToString(PPU_BackgroundPatternShiftRegisterL, 2).PadLeft(16, '0') + \"\\t\";\n            string BSR_Hi = \"BSRH: \" + Convert.ToString(PPU_BackgroundPatternShiftRegisterH, 2).PadLeft(16, '0') + \"\\t\";\n\n            string EightCycleRead = \"\";\n            if ((PPU_Dot >= 1 && PPU_Dot <= 256) || (PPU_Dot >= 321 && PPU_Dot <= 336)) // if this is a visible pixel, or preparing the start of next scanline\n            {\n                if(PPU_Mask_ShowSprites || PPU_Mask_ShowBackground)\n                {\n                    EightCycleRead =  \"8CycleReadTick: \" + ((byte)((PPU_Dot + 7) & 7)).ToString() + \"\\t\";\n                }\n                else\n                {\n                    EightCycleRead = \"8CycleReadTick: -\\t\";\n                }\n            }\n\n            string LogLine = \"(\" + PPU_Scanline.ToString() + \", \" + PPU_Dot.ToString() + \")  \\t\" + Addr + Octal + EightCycleRead + dotColor + enabled + MMC3 + ALE + RD + BSR_Lo + BSR_Hi;\n            DebugLog.AppendLine(LogLine);\n        }\n\n        public List<Byte> SaveState()\n        {\n            List<Byte> State = new List<byte>();\n\n            State.Add((byte)programCounter);\n            State.Add((byte)(programCounter >> 8));\n            State.Add((byte)addressBus);\n            State.Add((byte)(addressBus >> 8));\n            State.Add((byte)temporaryAddress);\n            State.Add((byte)(temporaryAddress >> 8));\n            State.Add((byte)OAMAddressBus);\n            State.Add((byte)(OAMAddressBus >> 8));\n            State.Add((byte)PPU_v);\n            State.Add((byte)(PPU_v >> 8));\n            State.Add((byte)PPU_t);\n            State.Add((byte)(PPU_t >> 8));\n\n            State.Add((byte)totalCycles);\n            State.Add((byte)(totalCycles >> 8));\n            State.Add((byte)(totalCycles >> 16));\n            State.Add((byte)(totalCycles >> 24));\n\n            State.Add(PPUClock);\n            State.Add(CPUClock);\n\n            State.Add(operationCycle);\n            State.Add(opCode);\n\n            State.Add(dl);\n            State.Add(dataBus);\n            State.Add(A);\n            State.Add(X);\n            State.Add(Y);\n            State.Add(stackPointer);\n            status = flag_Carry ? (byte)0x01 : (byte)0;\n            status += flag_Zero ? (byte)0x02 : (byte)0;\n            status += flag_Interrupt ? (byte)0x04 : (byte)0;\n            status += flag_Decimal ? (byte)0x08 : (byte)0;\n            status += flag_Overflow ? (byte)0x40 : (byte)0;\n            status += flag_Negative ? (byte)0x80 : (byte)0;\n            State.Add(status);\n\n            State.Add(specialBus);\n            State.Add(H);\n            State.Add((byte)(IgnoreH ? 1 : 0));\n\n            State.Add((byte)(CPU_Read ? 1 : 0));\n            State.Add((byte)(DoBRK ? 1 : 0));\n            State.Add((byte)(DoNMI ? 1 : 0));\n            State.Add((byte)(DoIRQ ? 1 : 0));\n            State.Add((byte)(DoReset ? 1 : 0));\n            State.Add((byte)(DoOAMDMA ? 1 : 0));\n            State.Add((byte)(FirstCycleOfOAMDMA ? 1 : 0));\n            State.Add((byte)(DoDMCDMA ? 1 : 0));\n            State.Add(DMCDMADelay);\n            State.Add(CannotRunDMCDMARightNow);\n            State.Add(DMAPage);\n            State.Add(DMAAddress);\n            State.Add((byte)(APU_ControllerPortsStrobing ? 1 : 0));\n            State.Add((byte)(APU_ControllerPortsStrobed ? 1 : 0));\n            State.Add(ControllerPort1);\n            State.Add(ControllerPort2);\n            State.Add(ControllerShiftRegister1);\n            State.Add(ControllerShiftRegister2);\n            State.Add(Controller1ShiftCounter);\n            State.Add(Controller2ShiftCounter);\n            State.Add((byte)(dataPinsAreNotFloating ? 1 : 0));\n\n            State.Add((byte)(APU_PutCycle ? 1 : 0));\n            State.Add((byte)(APU_Status_DMCInterrupt ? 1 : 0));\n            State.Add((byte)(APU_Status_FrameInterrupt ? 1 : 0));\n            State.Add((byte)(APU_Status_DMC ? 1 : 0));\n            State.Add((byte)(APU_Status_DelayedDMC ? 1 : 0));\n            State.Add((byte)(APU_Status_Noise ? 1 : 0));\n            State.Add((byte)(APU_Status_Triangle ? 1 : 0));\n            State.Add((byte)(APU_Status_Pulse2 ? 1 : 0));\n            State.Add((byte)(APU_Status_Pulse1 ? 1 : 0));\n            State.Add((byte)(Clearing_APU_FrameInterrupt ? 1 : 0));\n            State.Add(APU_DelayedDMC4015);\n            State.Add((byte)(APU_ImplicitAbortDMC4015 ? 1 : 0));\n            State.Add((byte)(APU_SetImplicitAbortDMC4015 ? 1 : 0));\n            foreach (Byte b in APU_Register) { State.Add(b); }\n            State.Add((byte)(APU_FrameCounterMode ? 1 : 0));\n            State.Add((byte)(APU_FrameCounterInhibitIRQ ? 1 : 0));\n            State.Add(APU_FrameCounterReset);\n            State.Add((byte)APU_Framecounter);\n            State.Add((byte)(APU_Framecounter >> 8));\n            State.Add((byte)(APU_QuarterFrameClock ? 1 : 0));\n            State.Add((byte)(APU_HalfFrameClock ? 1 : 0));\n            State.Add((byte)(APU_Envelope_StartFlag ? 1 : 0));\n            State.Add((byte)(APU_Envelope_DividerClock ? 1 : 0));\n            State.Add(APU_Envelope_DecayLevel);\n            State.Add(APU_LengthCounter_Pulse1);\n            State.Add(APU_LengthCounter_Pulse2);\n            State.Add(APU_LengthCounter_Triangle);\n            State.Add(APU_LengthCounter_Noise);\n            State.Add((byte)(APU_LengthCounter_HaltPulse1 ? 1 : 0));\n            State.Add((byte)(APU_LengthCounter_HaltPulse2 ? 1 : 0));\n            State.Add((byte)(APU_LengthCounter_HaltTriangle ? 1 : 0));\n            State.Add((byte)(APU_LengthCounter_HaltNoise ? 1 : 0));\n            State.Add((byte)(APU_LengthCounter_ReloadPulse1 ? 1 : 0));\n            State.Add((byte)(APU_LengthCounter_ReloadPulse2 ? 1 : 0));\n            State.Add((byte)(APU_LengthCounter_ReloadTriangle ? 1 : 0));\n            State.Add((byte)(APU_LengthCounter_ReloadNoise ? 1 : 0));\n            State.Add(APU_LengthCounter_ReloadValuePulse1);\n            State.Add(APU_LengthCounter_ReloadValuePulse2);\n            State.Add(APU_LengthCounter_ReloadValueTriangle);\n            State.Add(APU_LengthCounter_ReloadValueNoise);\n            State.Add((byte)APU_ChannelTimer_Pulse1);\n            State.Add((byte)(APU_ChannelTimer_Pulse1 >> 8));\n            State.Add((byte)APU_ChannelTimer_Pulse2);\n            State.Add((byte)(APU_ChannelTimer_Pulse2 >> 8));\n            State.Add((byte)APU_ChannelTimer_Triangle);\n            State.Add((byte)(APU_ChannelTimer_Triangle >> 8));\n            State.Add((byte)APU_ChannelTimer_Noise);\n            State.Add((byte)(APU_ChannelTimer_Noise >> 8));\n            State.Add((byte)APU_ChannelTimer_DMC);\n            State.Add((byte)(APU_ChannelTimer_DMC >> 8));\n            State.Add((byte)(APU_DMC_EnableIRQ ? 1 : 0));\n            State.Add((byte)(APU_DMC_Loop ? 1 : 0));\n            State.Add((byte)APU_DMC_Rate);\n            State.Add((byte)(APU_DMC_Rate >> 8));\n            State.Add(APU_DMC_Output);\n            State.Add((byte)APU_DMC_SampleAddress);\n            State.Add((byte)(APU_DMC_SampleAddress >> 8));\n            State.Add((byte)APU_DMC_SampleLength);\n            State.Add((byte)(APU_DMC_SampleLength >> 8));\n            State.Add((byte)APU_DMC_BytesRemaining);\n            State.Add((byte)(APU_DMC_BytesRemaining >> 8));\n            State.Add(APU_DMC_Buffer);\n            State.Add((byte)APU_DMC_AddressCounter);\n            State.Add((byte)(APU_DMC_AddressCounter >> 8));\n            State.Add(APU_DMC_Shifter);\n            State.Add(APU_DMC_ShifterBitsRemaining);\n            State.Add((byte)(APU_Silent ? 1 : 0));\n\n            State.Add(SecondaryOAMSize);\n            State.Add(OAM2Address);\n            State.Add((byte)(SecondaryOAMFull ? 1 : 0));\n            State.Add(SpriteEvaluationTick);\n            State.Add((byte)(OAMAddressOverflowedDuringSpriteEvaluation ? 1 : 0));\n            State.Add(OAM2Address);\n            State.Add(PPUBus);\n            for (int i = 0; i < 8; i++)\n            {\n                State.Add((byte)PPUBusDecay[i]);\n                State.Add((byte)(PPUBusDecay[i] >> 8));\n                State.Add((byte)(PPUBusDecay[i] >> 16));\n                State.Add((byte)(PPUBusDecay[i] >> 24));\n            }\n            State.Add(PPUOAMAddress);\n            State.Add((byte)(PPUStatus_VBlank ? 1 : 0));\n            State.Add((byte)(PPUStatus_SpriteZeroHit ? 1 : 0));\n            State.Add((byte)(PPUStatus_SpriteOverflow ? 1 : 0));\n            State.Add((byte)(PPUStatus_PendingSpriteZeroHit ? 1 : 0));\n            State.Add((byte)(PPUStatus_PendingSpriteZeroHit2 ? 1 : 0));\n            State.Add((byte)(PPUStatus_SpriteZeroHit_Delayed ? 1 : 0));\n            State.Add((byte)(PPUStatus_SpriteOverflow_Delayed ? 1 : 0));\n\n            State.Add((byte)(PPU_Spritex16 ? 1 : 0));\n            State.Add((byte)PPU_Scanline);\n            State.Add((byte)(PPU_Scanline >> 8));\n            State.Add((byte)PPU_Dot);\n            State.Add((byte)(PPU_Dot >> 8));\n            State.Add((byte)(PPU_VRegisterChangedOutOfVBlank ? 1 : 0));\n            State.Add((byte)(PPU_OAMCorruptionRenderingDisabledOutOfVBlank ? 1 : 0));\n            State.Add((byte)(PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant ? 1 : 0));\n            State.Add((byte)(PPU_PendingOAMCorruption ? 1 : 0));\n            State.Add(PPU_OAMCorruptionIndex);\n            State.Add((byte)(PPU_OAMCorruptionRenderingEnabledOutOfVBlank ? 1 : 0));\n            State.Add((byte)(PPU_OAMEvaluationCorruptionOddCycle ? 1 : 0));\n            State.Add((byte)(PPU_OAMEvaluationObjectInRange ? 1 : 0));\n            State.Add((byte)(PPU_OAMEvaluationObjectInXRange ? 1 : 0));\n            State.Add((byte)(PPU_PaletteCorruptionRenderingDisabledOutOfVBlank ? 1 : 0));\n            State.Add(PPU_AttributeLatchRegister);\n            State.Add((byte)PPU_BackgroundAttributeShiftRegisterL);\n            State.Add((byte)(PPU_BackgroundAttributeShiftRegisterL >> 8));\n            State.Add((byte)PPU_BackgroundAttributeShiftRegisterH);\n            State.Add((byte)(PPU_BackgroundAttributeShiftRegisterH >> 8));\n            State.Add((byte)PPU_BackgroundPatternShiftRegisterL);\n            State.Add((byte)(PPU_BackgroundPatternShiftRegisterL >> 8));\n            State.Add((byte)PPU_BackgroundPatternShiftRegisterH);\n            State.Add((byte)(PPU_BackgroundPatternShiftRegisterH >> 8));\n            State.Add(PPU_FineXScroll);\n            for (int i = 0; i < 8; i++) { State.Add(PPU_SpriteShiftRegisterL[i]); }\n            for (int i = 0; i < 8; i++) { State.Add(PPU_SpriteShiftRegisterH[i]); }\n            for (int i = 0; i < 8; i++) { State.Add(PPU_SpriteAttribute[i]); }\n            for (int i = 0; i < 8; i++) { State.Add(PPU_SpritePattern[i]); }\n            for (int i = 0; i < 8; i++) { State.Add(PPU_SpriteXposition[i]); }\n            for (int i = 0; i < 8; i++) { State.Add(PPU_SpriteYposition[i]); }\n            for (int i = 0; i < 8; i++) { State.Add(PPU_SpriteShifterCounter[i]); }\n            State.Add((byte)(PPU_NextScanlineContainsSpriteZero ? 1 : 0));\n            State.Add((byte)(PPU_CurrentScanlineContainsSpriteZero ? 1 : 0));\n            State.Add(PPU_SpritePatternL);\n            State.Add(PPU_SpritePatternH);\n            State.Add((byte)(PPU_Mask_Greyscale ? 1 : 0));\n            State.Add((byte)(PPU_Mask_8PxShowBackground ? 1 : 0));\n            State.Add((byte)(PPU_Mask_8PxShowSprites ? 1 : 0));\n            State.Add((byte)(PPU_Mask_ShowBackground ? 1 : 0));\n            State.Add((byte)(PPU_Mask_ShowSprites ? 1 : 0));\n            State.Add((byte)(PPU_Mask_EmphasizeRed ? 1 : 0));\n            State.Add((byte)(PPU_Mask_EmphasizeGreen ? 1 : 0));\n            State.Add((byte)(PPU_Mask_EmphasizeBlue ? 1 : 0));\n            State.Add((byte)(PPU_Mask_ShowBackground_Delayed ? 1 : 0));\n            State.Add((byte)(PPU_Mask_ShowSprites_Delayed ? 1 : 0));\n            State.Add((byte)(PPU_Mask_ShowBackground_Instant ? 1 : 0));\n            State.Add((byte)(PPU_Mask_ShowSprites_Instant ? 1 : 0));\n            State.Add(PPU_LowBitPlane);\n            State.Add(PPU_HighBitPlane);\n            State.Add(PPU_Attribute);\n            State.Add((byte)(PPU_CanDetectSpriteZeroHit ? 1 : 0));\n            State.Add((byte)(PPU_A12_Prev ? 1 : 0));\n            State.Add((byte)(PPU_OddFrame ? 1 : 0));\n            State.Add(PaletteRAMAddress);\n            State.Add((byte)(ThisDotReadFromPaletteRAM ? 1 : 0));\n            State.Add((byte)(NMI_PinsSignal ? 1 : 0));\n            State.Add((byte)(NMI_PreviousPinsSignal ? 1 : 0));\n            State.Add((byte)(IRQ_LevelDetector ? 1 : 0));\n            State.Add((byte)(NMILine ? 1 : 0));\n            State.Add((byte)(IRQLine ? 1 : 0));\n            State.Add((byte)(CopyV ? 1 : 0));\n            State.Add((byte)(SkippedPreRenderDot341 ? 1 : 0));\n            State.Add((byte)(OamCorruptedOnOddCycle ? 1 : 0));\n            State.Add(PPU_OAMLatch);\n            State.Add(PPU_RenderTemp);\n            State.Add((byte)(PPU_Commit_NametableFetch ? 1 : 0));\n            State.Add((byte)(PPU_Commit_AttributeFetch ? 1 : 0));\n            State.Add((byte)(PPU_Commit_PatternLowFetch ? 1 : 0));\n            State.Add((byte)(PPU_Commit_PatternHighFetch ? 1 : 0));\n\n            State.Add((byte)PPU_VRAM_MysteryAddress);\n            State.Add((byte)(PPU_VRAM_MysteryAddress >> 8));\n            State.Add((byte)PPU_AddressBus);\n            State.Add((byte)(PPU_AddressBus >> 8));\n            State.Add(PPU_Update2006Delay);\n            State.Add(PPU_Update2005Delay);\n            State.Add(PPU_Update2005Value);\n            State.Add(PPU_Update2001Value);\n            State.Add((byte)PPU_Update2006Value);\n            State.Add((byte)(PPU_Update2006Value >> 8));\n            State.Add((byte)PPU_Update2006Value_Temp);\n            State.Add((byte)(PPU_Update2006Value_Temp >> 8));\n            State.Add((byte)(PPU_WasRenderingBefore2001Write ? 1 : 0));\n            State.Add(PPU_ReadBuffer);\n            State.Add((byte)(PPUAddrLatch ? 1 : 0));\n            State.Add((byte)(PPUControlIncrementMode32 ? 1 : 0));\n            State.Add((byte)(PPUControl_NMIEnabled ? 1 : 0));\n            State.Add((byte)(PPU_PatternSelect_Sprites ? 1 : 0));\n            State.Add((byte)(PPU_PatternSelect_Background ? 1 : 0));\n            State.Add((byte)(PPU_PendingVBlank ? 1 : 0));\n\n            State.Add((byte)(PPU_VSET ? 1 : 0));\n            State.Add((byte)(PPU_VSET_Latch1 ? 1 : 0));\n            State.Add((byte)(PPU_VSET_Latch2 ? 1 : 0));\n            State.Add((byte)(PPU_Read2002 ? 1 : 0));\n\n            State.Add((byte)(OAMDMA_Aligned ? 1 : 0));\n            State.Add((byte)(OAMDMA_Halt ? 1 : 0));\n            State.Add((byte)(DMCDMA_Halt ? 1 : 0));\n            State.Add(OAM_InternalBus);\n\n            State.Add((byte)PPU_PatternAddressRegister_CHR);\n            State.Add((byte)(PPU_PatternAddressRegister_CHR >> 8));\n            State.Add((byte)(PPU_ALE ? 1 : 0));\n            State.Add(PPU_OctalLatch);\n\n            State.Add((byte)(PPU_2007_Read ? 1 : 0));\n            State.Add((byte)(PPU_2007_Read_SR ? 1 : 0));\n            for (int i = 0; i < PPU_2007_Read_Latches.Length; i++) { State.Add((byte)(PPU_2007_Read_Latches[i] ? 1 : 0)); }\n            State.Add((byte)(PPU_2007_PD_RB ? 1 : 0));\n            State.Add((byte)(PPU_2007_ReadALE ? 1 : 0));\n            State.Add((byte)(PPU_2007_Read_H0_Latch ? 1 : 0));\n            State.Add((byte)(PPU_2007_Read_XRB ? 1 : 0));\n            State.Add((byte)(PPU_READ ? 1 : 0));\n            State.Add((byte)(PPU_2007_Write ? 1 : 0));\n            State.Add((byte)(PPU_2007_Write_SR ? 1 : 0));\n            for (int i = 0; i < PPU_2007_Write_Latches.Length; i++) { State.Add((byte)(PPU_2007_Write_Latches[i] ? 1 : 0)); }\n            State.Add((byte)(PPU_2007_DB_PAR ? 1 : 0));\n            State.Add((byte)(PPU_2007_WriteALE ? 1 : 0));\n            State.Add((byte)(PPU_2007_TStep_Latch ? 1 : 0));\n            State.Add((byte)(PPU_2007_TStep ? 1 : 0));\n            State.Add((byte)(PPU_2007_BLNK_Latch ? 1 : 0));\n            State.Add((byte)(PPU_2007_PaletteRAMEnable ? 1 : 0));\n            State.Add(PPU_2007_WriteData);\n            State.Add((byte)(PPU_WRITE ? 1 : 0));\n\n            State.Add(PPU_Update2001Delay);              // TEMPORARY\n            State.Add(PPU_Update2001OAMCorruptionDelay); // TEMPORARY\n            State.Add(PPU_Update2001EmphasisBitsDelay);  // TEMPORARY\n\n            foreach (Byte b in RAM) { State.Add(b); }\n            foreach (Byte b in VRAM) { State.Add(b); }\n            foreach (Byte b in OAM) { State.Add(b); }\n            foreach (Byte b in OAM2) { State.Add(b); }\n            foreach (Byte b in PaletteRAM) { State.Add(b); }\n\n            List<byte> MapperBytes = Cart.MapperChip.SaveMapperRegisters();\n            for (int i = 0; i < MapperBytes.Count; i++)\n            {\n                State.Add(MapperBytes[i]);\n            }\n\n            return State;\n        }\n\n        public void LoadState(List<byte> State)\n        {\n            int p = 0;\n            programCounter = State[p++];\n            programCounter |= (ushort)(State[p++] << 8);\n            addressBus = State[p++];\n            addressBus |= (ushort)(State[p++] << 8);\n            temporaryAddress = State[p++];\n            temporaryAddress |= (ushort)(State[p++] << 8);\n            OAMAddressBus = State[p++];\n            OAMAddressBus |= (ushort)(State[p++] << 8);\n            PPU_v = State[p++];\n            PPU_v |= (ushort)(State[p++] << 8);\n            PPU_t = State[p++];\n            PPU_t |= (ushort)(State[p++] << 8);\n\n            totalCycles = State[p++];\n            totalCycles |= (State[p++] << 8);\n            totalCycles |= (State[p++] << 16);\n            totalCycles |= (State[p++] << 24);\n\n            PPUClock = State[p++];\n            CPUClock = State[p++];\n\n            operationCycle = State[p++];\n            opCode = State[p++];\n\n            dl = State[p++];\n            dataBus = State[p++];\n            A = State[p++];\n            X = State[p++];\n            Y = State[p++];\n            stackPointer = State[p++];\n\n            status = State[p++];\n            flag_Carry = (status & 1) == 1;\n            flag_Zero = ((status & 0x02) >> 1) == 1;\n            flag_Interrupt = ((status & 0x04) >> 2) == 1;\n            flag_Decimal = ((status & 0x08) >> 3) == 1;\n            flag_Overflow = ((status & 0x40) >> 6) == 1;\n            flag_Negative = ((status & 0x80) >> 7) == 1;\n\n            specialBus = State[p++];\n            H = State[p++];\n            IgnoreH = (State[p++] & 1) == 1;\n\n            CPU_Read = (State[p++] & 1) == 1;\n            DoBRK = (State[p++] & 1) == 1;\n            DoNMI = (State[p++] & 1) == 1;\n            DoIRQ = (State[p++] & 1) == 1;\n            DoReset = (State[p++] & 1) == 1;\n            DoOAMDMA = (State[p++] & 1) == 1;\n            FirstCycleOfOAMDMA = (State[p++] & 1) == 1;\n            DoDMCDMA = (State[p++] & 1) == 1;\n            DMCDMADelay = State[p++];\n            CannotRunDMCDMARightNow = State[p++];\n            DMAPage = State[p++];\n            DMAAddress = State[p++];\n            APU_ControllerPortsStrobing = (State[p++] & 1) == 1;\n            APU_ControllerPortsStrobed = (State[p++] & 1) == 1;\n            ControllerPort1 = State[p++];\n            ControllerPort2 = State[p++];\n            ControllerShiftRegister1 = State[p++];\n            ControllerShiftRegister2 = State[p++];\n            Controller1ShiftCounter = State[p++];\n            Controller2ShiftCounter = State[p++];\n            dataPinsAreNotFloating = (State[p++] & 1) == 1;\n\n            APU_PutCycle = (State[p++] & 1) == 1;\n            APU_Status_DMCInterrupt = (State[p++] & 1) == 1;\n            APU_Status_FrameInterrupt = (State[p++] & 1) == 1;\n            APU_Status_DMC = (State[p++] & 1) == 1;\n            APU_Status_DelayedDMC = (State[p++] & 1) == 1;\n            APU_Status_Noise = (State[p++] & 1) == 1;\n            APU_Status_Triangle = (State[p++] & 1) == 1;\n            APU_Status_Pulse2 = (State[p++] & 1) == 1;\n            APU_Status_Pulse1 = (State[p++] & 1) == 1;\n            Clearing_APU_FrameInterrupt = (State[p++] & 1) == 1;\n            APU_DelayedDMC4015 = State[p++];\n            APU_ImplicitAbortDMC4015 = (State[p++] & 1) == 1;\n            APU_SetImplicitAbortDMC4015 = (State[p++] & 1) == 1;\n            for (int i = 0; i < APU_Register.Length; i++) { APU_Register[i] = State[p++]; }\n            APU_FrameCounterMode = (State[p++] & 1) == 1;\n            APU_FrameCounterInhibitIRQ = (State[p++] & 1) == 1;\n            APU_FrameCounterReset = State[p++];\n            APU_Framecounter = State[p++];\n            APU_Framecounter |= (ushort)(State[p++] << 8);\n            APU_QuarterFrameClock = (State[p++] & 1) == 1;\n            APU_HalfFrameClock = (State[p++] & 1) == 1;\n            APU_Envelope_StartFlag = (State[p++] & 1) == 1;\n            APU_Envelope_DividerClock = (State[p++] & 1) == 1;\n            APU_Envelope_DecayLevel = State[p++];\n            APU_LengthCounter_Pulse1 = State[p++];\n            APU_LengthCounter_Pulse2 = State[p++];\n            APU_LengthCounter_Triangle = State[p++];\n            APU_LengthCounter_Noise = State[p++];\n            APU_LengthCounter_HaltPulse1 = (State[p++] & 1) == 1;\n            APU_LengthCounter_HaltPulse2 = (State[p++] & 1) == 1;\n            APU_LengthCounter_HaltTriangle = (State[p++] & 1) == 1;\n            APU_LengthCounter_HaltNoise = (State[p++] & 1) == 1;\n            APU_LengthCounter_ReloadPulse1 = (State[p++] & 1) == 1;\n            APU_LengthCounter_ReloadPulse2 = (State[p++] & 1) == 1;\n            APU_LengthCounter_ReloadTriangle = (State[p++] & 1) == 1;\n            APU_LengthCounter_ReloadNoise = (State[p++] & 1) == 1;\n            APU_LengthCounter_ReloadValuePulse1 = State[p++];\n            APU_LengthCounter_ReloadValuePulse2 = State[p++];\n            APU_LengthCounter_ReloadValueTriangle = State[p++];\n            APU_LengthCounter_ReloadValueNoise = State[p++];\n            APU_ChannelTimer_Pulse1 = State[p++];\n            APU_ChannelTimer_Pulse1 |= (ushort)(State[p++] << 8);\n            APU_ChannelTimer_Pulse2 = State[p++];\n            APU_ChannelTimer_Pulse2 |= (ushort)(State[p++] << 8);\n            APU_ChannelTimer_Triangle = State[p++];\n            APU_ChannelTimer_Triangle |= (ushort)(State[p++] << 8);\n            APU_ChannelTimer_Noise = State[p++];\n            APU_ChannelTimer_Noise |= (ushort)(State[p++] << 8);\n            APU_ChannelTimer_DMC = State[p++];\n            APU_ChannelTimer_DMC |= (ushort)(State[p++] << 8);\n            APU_DMC_EnableIRQ = (State[p++] & 1) == 1;\n            APU_DMC_Loop = (State[p++] & 1) == 1;\n            APU_DMC_Rate = State[p++];\n            APU_DMC_Rate |= (ushort)(State[p++] << 8);\n            APU_DMC_Output = State[p++];\n            APU_DMC_SampleAddress = State[p++];\n            APU_DMC_SampleAddress |= (ushort)(State[p++] << 8);\n            APU_DMC_SampleLength = State[p++];\n            APU_DMC_SampleLength |= (ushort)(State[p++] << 8);\n            APU_DMC_BytesRemaining = State[p++];\n            APU_DMC_BytesRemaining |= (ushort)(State[p++] << 8);\n            APU_DMC_Buffer = State[p++];\n            APU_DMC_AddressCounter = State[p++];\n            APU_DMC_AddressCounter |= (ushort)(State[p++] << 8);\n            APU_DMC_Shifter = State[p++];\n            APU_DMC_ShifterBitsRemaining = State[p++];\n            APU_Silent = (State[p++] & 1) == 1;\n\n            SecondaryOAMSize = State[p++];\n            OAM2Address = State[p++];\n            SecondaryOAMFull = (State[p++] & 1) == 1;\n            SpriteEvaluationTick = State[p++];\n            OAMAddressOverflowedDuringSpriteEvaluation = (State[p++] & 1) == 1;\n            OAM2Address = State[p++];\n            PPUBus = State[p++];\n            for (int i = 0; i < 8; i++)\n            {\n                PPUBusDecay[i] = State[p++];\n                PPUBusDecay[i] |= (State[p++] << 8);\n                PPUBusDecay[i] |= (State[p++] << 16);\n                PPUBusDecay[i] |= (State[p++] << 24);\n            }\n            PPUOAMAddress = State[p++];\n            PPUStatus_VBlank = (State[p++] & 1) == 1;\n            PPUStatus_SpriteZeroHit = (State[p++] & 1) == 1;\n            PPUStatus_SpriteOverflow = (State[p++] & 1) == 1;\n            PPUStatus_PendingSpriteZeroHit = (State[p++] & 1) == 1;\n            PPUStatus_PendingSpriteZeroHit2 = (State[p++] & 1) == 1;\n            PPUStatus_SpriteZeroHit_Delayed = (State[p++] & 1) == 1;\n            PPUStatus_SpriteOverflow_Delayed = (State[p++] & 1) == 1;\n\n            PPU_Spritex16 = (State[p++] & 1) == 1;\n            PPU_Scanline = State[p++];\n            PPU_Scanline |= (ushort)(State[p++] << 8);\n            PPU_Dot = State[p++];\n            PPU_Dot |= (ushort)(State[p++] << 8);\n            PPU_VRegisterChangedOutOfVBlank = (State[p++] & 1) == 1;\n            PPU_OAMCorruptionRenderingDisabledOutOfVBlank = (State[p++] & 1) == 1;\n            PPU_OAMCorruptionRenderingDisabledOutOfVBlank_Instant = (State[p++] & 1) == 1;\n            PPU_PendingOAMCorruption = (State[p++] & 1) == 1;\n            PPU_OAMCorruptionIndex = State[p++];\n            PPU_OAMCorruptionRenderingEnabledOutOfVBlank = (State[p++] & 1) == 1;\n            PPU_OAMEvaluationCorruptionOddCycle = (State[p++] & 1) == 1;\n            PPU_OAMEvaluationObjectInRange = (State[p++] & 1) == 1;\n            PPU_OAMEvaluationObjectInXRange = (State[p++] & 1) == 1;\n            PPU_PaletteCorruptionRenderingDisabledOutOfVBlank = (State[p++] & 1) == 1;\n            PPU_AttributeLatchRegister = State[p++];\n            PPU_BackgroundAttributeShiftRegisterL = State[p++];\n            PPU_BackgroundAttributeShiftRegisterL |= (ushort)(State[p++] << 8);\n            PPU_BackgroundAttributeShiftRegisterH = State[p++];\n            PPU_BackgroundAttributeShiftRegisterH |= (ushort)(State[p++] << 8);\n            PPU_BackgroundPatternShiftRegisterL = State[p++];\n            PPU_BackgroundPatternShiftRegisterL |= (ushort)(State[p++] << 8);\n            PPU_BackgroundPatternShiftRegisterH = State[p++];\n            PPU_BackgroundPatternShiftRegisterH |= (ushort)(State[p++] << 8);\n            PPU_FineXScroll = State[p++];\n            for (int i = 0; i < 8; i++) { PPU_SpriteShiftRegisterL[i] = State[p++]; }\n            for (int i = 0; i < 8; i++) { PPU_SpriteShiftRegisterH[i] = State[p++]; }\n            for (int i = 0; i < 8; i++) { PPU_SpriteAttribute[i] = State[p++]; }\n            for (int i = 0; i < 8; i++) { PPU_SpritePattern[i] = State[p++]; }\n            for (int i = 0; i < 8; i++) { PPU_SpriteXposition[i] = State[p++]; }\n            for (int i = 0; i < 8; i++) { PPU_SpriteYposition[i] = State[p++]; }\n            for (int i = 0; i < 8; i++) { PPU_SpriteShifterCounter[i] = State[p++]; }\n            PPU_NextScanlineContainsSpriteZero = (State[p++] & 1) == 1;\n            PPU_CurrentScanlineContainsSpriteZero = (State[p++] & 1) == 1;\n            PPU_SpritePatternL = State[p++];\n            PPU_SpritePatternH = State[p++];\n            PPU_Mask_Greyscale = (State[p++] & 1) == 1;\n            PPU_Mask_8PxShowBackground = (State[p++] & 1) == 1;\n            PPU_Mask_8PxShowSprites = (State[p++] & 1) == 1;\n            PPU_Mask_ShowBackground = (State[p++] & 1) == 1;\n            PPU_Mask_ShowSprites = (State[p++] & 1) == 1;\n            PPU_Mask_EmphasizeRed = (State[p++] & 1) == 1;\n            PPU_Mask_EmphasizeGreen = (State[p++] & 1) == 1;\n            PPU_Mask_EmphasizeBlue = (State[p++] & 1) == 1;\n            PPU_Mask_ShowBackground_Delayed = (State[p++] & 1) == 1;\n            PPU_Mask_ShowSprites_Delayed = (State[p++] & 1) == 1;\n            PPU_Mask_ShowBackground_Instant = (State[p++] & 1) == 1;\n            PPU_Mask_ShowSprites_Instant = (State[p++] & 1) == 1;\n            PPU_LowBitPlane = State[p++];\n            PPU_HighBitPlane = State[p++];\n            PPU_Attribute = State[p++];\n            PPU_CanDetectSpriteZeroHit = (State[p++] & 1) == 1;\n            PPU_A12_Prev = (State[p++] & 1) == 1;\n            PPU_OddFrame = (State[p++] & 1) == 1;\n            PaletteRAMAddress = State[p++];\n            ThisDotReadFromPaletteRAM = (State[p++] & 1) == 1;\n            NMI_PinsSignal = (State[p++] & 1) == 1;\n            NMI_PreviousPinsSignal = (State[p++] & 1) == 1;\n            IRQ_LevelDetector = (State[p++] & 1) == 1;\n            NMILine = (State[p++] & 1) == 1;\n            IRQLine = (State[p++] & 1) == 1;\n            CopyV = (State[p++] & 1) == 1;\n            SkippedPreRenderDot341 = (State[p++] & 1) == 1;\n            OamCorruptedOnOddCycle = (State[p++] & 1) == 1;\n            PPU_OAMLatch = State[p++];\n            PPU_RenderTemp = State[p++];\n            PPU_Commit_NametableFetch = (State[p++] & 1) == 1;\n            PPU_Commit_AttributeFetch = (State[p++] & 1) == 1;\n            PPU_Commit_PatternLowFetch = (State[p++] & 1) == 1;\n            PPU_Commit_PatternHighFetch = (State[p++] & 1) == 1;\n\n            PPU_VRAM_MysteryAddress = State[p++];\n            PPU_VRAM_MysteryAddress |= (ushort)(State[p++] << 8);\n            PPU_AddressBus = State[p++];\n            PPU_AddressBus |= (ushort)(State[p++] << 8);\n            PPU_Update2006Delay = State[p++];\n            PPU_Update2005Delay = State[p++];\n            PPU_Update2005Value = State[p++];\n            PPU_Update2001Value = State[p++];\n            PPU_Update2006Value = State[p++];\n            PPU_Update2006Value |= (ushort)(State[p++] << 8);\n            PPU_Update2006Value_Temp = State[p++];\n            PPU_Update2006Value_Temp |= (ushort)(State[p++] << 8);\n            PPU_WasRenderingBefore2001Write = (State[p++] & 1) == 1;\n            PPU_ReadBuffer = State[p++];\n            PPUAddrLatch = (State[p++] & 1) == 1;\n            PPUControlIncrementMode32 = (State[p++] & 1) == 1;\n            PPUControl_NMIEnabled = (State[p++] & 1) == 1;\n            PPU_PatternSelect_Sprites = (State[p++] & 1) == 1;\n            PPU_PatternSelect_Background = (State[p++] & 1) == 1;\n            PPU_PendingVBlank = (State[p++] & 1) == 1;\n\n            PPU_VSET = (State[p++] & 1) == 1;\n            PPU_VSET_Latch1 = (State[p++] & 1) == 1;\n            PPU_VSET_Latch2 = (State[p++] & 1) == 1;\n            PPU_Read2002 = (State[p++] & 1) == 1;\n\n            OAMDMA_Aligned = (State[p++] & 1) == 1;\n            OAMDMA_Halt = (State[p++] & 1) == 1;\n            DMCDMA_Halt = (State[p++] & 1) == 1;\n            OAM_InternalBus = State[p++];\n\n            PPU_PatternAddressRegister_CHR = State[p++];\n            PPU_PatternAddressRegister_CHR |= (ushort)(State[p++] << 8);\n            PPU_ALE = (State[p++] & 1) == 1;\n            PPU_OctalLatch = State[p++];\n\n            PPU_2007_Read = (State[p++] & 1) == 1;\n            PPU_2007_Read_SR = (State[p++] & 1) == 1;\n            for (int i = 0; i < PPU_2007_Read_Latches.Length; i++) { PPU_2007_Read_Latches[i] = (State[p++] & 1) == 1; }\n            PPU_2007_PD_RB = (State[p++] & 1) == 1;\n            PPU_2007_ReadALE = (State[p++] & 1) == 1;\n            PPU_2007_Read_H0_Latch = (State[p++] & 1) == 1;\n            PPU_2007_Read_XRB = (State[p++] & 1) == 1;\n            PPU_READ = (State[p++] & 1) == 1;\n            PPU_2007_Write = (State[p++] & 1) == 1;\n            PPU_2007_Write_SR = (State[p++] & 1) == 1;\n            for (int i = 0; i < PPU_2007_Write_Latches.Length; i++) { PPU_2007_Write_Latches[i] = (State[p++] & 1) == 1; }\n            PPU_2007_DB_PAR = (State[p++] & 1) == 1;\n            PPU_2007_WriteALE = (State[p++] & 1) == 1;\n            PPU_2007_TStep_Latch = (State[p++] & 1) == 1;\n            PPU_2007_TStep = (State[p++] & 1) == 1;\n            PPU_2007_BLNK_Latch = (State[p++] & 1) == 1;\n            PPU_2007_PaletteRAMEnable = (State[p++] & 1) == 1;\n            PPU_2007_WriteData = State[p++];\n            PPU_WRITE = (State[p++] & 1) == 1;\n            \n            PPU_Update2001Delay = State[p++];              //TOMPORARY\n            PPU_Update2001OAMCorruptionDelay = State[p++]; //TOMPORARY\n            PPU_Update2001EmphasisBitsDelay = State[p++];  //TOMPORARY\n\n            for (int i = 0; i < RAM.Length; i++) { RAM[i] = State[p++]; }\n            for (int i = 0; i < VRAM.Length; i++) { VRAM[i] = State[p++]; }\n            for (int i = 0; i < OAM.Length; i++) { OAM[i] = State[p++]; }\n            for (int i = 0; i < OAM2.Length; i++) { OAM2[i] = State[p++]; }\n            for (int i = 0; i < PaletteRAM.Length; i++) { PaletteRAM[i] = State[p++]; }\n\n            Cart.MapperChip.LoadMapperRegisters(State, p, out p);\n        }\n\n        public void Dispose()\n        {\n            Cart = null;\n            Screen.Dispose();\n            BorderedScreen.Dispose();\n            NTSCScreen.Dispose();\n            BorderedNTSCScreen.Dispose();\n        }\n\n    }\n\n    public class DirectBitmap : IDisposable\n    {\n        // This class was copied from Stack Overflow\n        // Writing to the standard Bitmap class is slow, so this class exists as a faster alternative.\n        public Bitmap Bitmap { get; private set; }\n        public Int32[] Bits { get; private set; }\n        public bool Disposed { get; private set; }\n        public int Height { get; private set; }\n        public int Width { get; private set; }\n\n        protected GCHandle BitsHandle { get; private set; }\n\n        public DirectBitmap(int width, int height)\n        {\n            Width = width;\n            Height = height;\n            Bits = new Int32[width * height];\n            BitsHandle = GCHandle.Alloc(Bits, GCHandleType.Pinned);\n            Bitmap = new Bitmap(width, height, width * 4, PixelFormat.Format32bppPArgb, BitsHandle.AddrOfPinnedObject());\n        }\n\n        public void SetPixel(int x, int y, Color color)\n        {\n            int index = x + (y * Width);\n            int col = color.ToArgb();\n\n            Bits[index] = col;\n        }\n\n        public void SetPixel(int x, int y, int colorRGBA)\n        {\n            int index = x + (y * Width);\n            Bits[index] = colorRGBA;\n        }\n\n        public Color GetPixel(int x, int y)\n        {\n            int index = x + (y * Width);\n            int col = Bits[index];\n            Color result = Color.FromArgb(col);\n\n            return result;\n        }\n\n        public void Dispose()\n        {\n            if (Disposed) return;\n            Disposed = true;\n            Bitmap.Dispose();\n            BitsHandle.Free();\n        }\n    }\n\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2025 Chris Siebert\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Program.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing System.Windows.Forms;\n\nnamespace TriCNES\n{\n    internal static class Program\n    {\n        /// <summary>\n        /// The main entry point for the application.\n        /// </summary>\n        [STAThread]\n        static void Main()\n        {\n            Application.EnableVisualStyles();\n            Application.SetCompatibleTextRenderingDefault(false);\n            Application.Run(new TriCNESGUI());\n        }\n    }\n}\n"
  },
  {
    "path": "Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following\n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"TriCNES\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"TriCNES\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2024\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Setting ComVisible to false makes the types in this assembly not visible\n// to COM components.  If you need to access a type in this assembly from\n// COM, set the ComVisible attribute to true on that type.\n[assembly: ComVisible(false)]\n\n// The following GUID is for the ID of the typelib if this project is exposed to COM\n[assembly: Guid(\"b53c8a3b-8f4f-4837-99a0-47d7d9fe757f\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version\n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers\n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n"
  },
  {
    "path": "Properties/Resources.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//     Runtime Version:4.0.30319.42000\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace TriCNES.Properties\n{\n\n\n    /// <summary>\n    ///   A strongly-typed resource class, for looking up localized strings, etc.\n    /// </summary>\n    // This class was auto-generated by the StronglyTypedResourceBuilder\n    // class via a tool like ResGen or Visual Studio.\n    // To add or remove a member, edit your .ResX file then rerun ResGen\n    // with the /str option, or rebuild your VS project.\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"System.Resources.Tools.StronglyTypedResourceBuilder\", \"4.0.0.0\")]\n    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    internal class Resources\n    {\n\n        private static global::System.Resources.ResourceManager resourceMan;\n\n        private static global::System.Globalization.CultureInfo resourceCulture;\n\n        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute(\"Microsoft.Performance\", \"CA1811:AvoidUncalledPrivateCode\")]\n        internal Resources()\n        {\n        }\n\n        /// <summary>\n        ///   Returns the cached ResourceManager instance used by this class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Resources.ResourceManager ResourceManager\n        {\n            get\n            {\n                if ((resourceMan == null))\n                {\n                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager(\"TriCNES.Properties.Resources\", typeof(Resources).Assembly);\n                    resourceMan = temp;\n                }\n                return resourceMan;\n            }\n        }\n\n        /// <summary>\n        ///   Overrides the current thread's CurrentUICulture property for all\n        ///   resource lookups using this strongly typed resource class.\n        /// </summary>\n        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\n        internal static global::System.Globalization.CultureInfo Culture\n        {\n            get\n            {\n                return resourceCulture;\n            }\n            set\n            {\n                resourceCulture = value;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Properties/Resources.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n</root>"
  },
  {
    "path": "Properties/Settings.Designer.cs",
    "content": "﻿//------------------------------------------------------------------------------\n// <auto-generated>\n//     This code was generated by a tool.\n//     Runtime Version:4.0.30319.42000\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// </auto-generated>\n//------------------------------------------------------------------------------\n\nnamespace TriCNES.Properties\n{\n\n\n    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator\", \"11.0.0.0\")]\n    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase\n    {\n\n        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));\n\n        public static Settings Default\n        {\n            get\n            {\n                return defaultInstance;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Properties/Settings.settings",
    "content": "﻿<?xml version='1.0' encoding='utf-8'?>\n<SettingsFile xmlns=\"http://schemas.microsoft.com/VisualStudio/2004/01/settings\" CurrentProfile=\"(Default)\">\n  <Profiles>\n    <Profile Name=\"(Default)\" />\n  </Profiles>\n  <Settings />\n</SettingsFile>\n"
  },
  {
    "path": "README.md",
    "content": "# TriCNES\n\nTriCNES, or \"Coin's Contrabulous Cartswapulator\", is a Nintendo Entertainment System emulator written by Chris \"100th_Coin\" Siebert with a focus on test-driven accuracy. This emulator was originally made in order to experiment with a theorhetical arbitary code exploit I created titled \"Intercycle Cartridge Swapping\" where the NES cartridge is replaced every CPU cycle in order to run custom code. Intercycle Cartridge Swapping was later verified to work on real hardware by Youtube user Decrazyo.  \n\nThis NES emulator was built from the ground up starting from a blank .net winforms project\n\n# Limitations\n\nThis emulator does not produce audio.  \nThis emulator only accepts inputs in the form of a TAS file.  \nThis emulator can only run NTSC cartridges properly.  \nThis emulator only supports the following mapper chips:\n* 0: NROM\n* 1: MMC1\n* 2: UxROM\n* 3: CNROM\n* 4: MMC3 (MMC6 support in the dev build)\n* 7: AOROM\n* 9: MMC2 (dev build)\n* 69: Sunsoft FME-7\n\n# Supported TAS file types\n\nDue to varying emulator accuracy, this emulator is not guaranteed to sync all TAS files. Despite this, it supports loading inputs from the following formats:\n* .3c2 (TriCNES) (dev build)\n* .3c3 (TriCNES TAS Timeline) (dev build)\n* .bk2 (Bizhawk)\n* .tasproj (Bizhawk's TAStudio)\n* .fm2 (FCEUX)\n* .fm3 (FCEUX's TAS Editor)\n* .fmv (Famtasia)\n* .r08 (Replay Device)\n\nIn addition to those TAS file types, my emulator can also load my very own intercycle-cart-swapping TAS format, .3ct.\n\n# The .3ct TAS file format\n\nTAS files that were made with the intention of swapping cartridges between cycles are stored in the following format.\n\nThe first line of the file is an integer, indicating how many cartridges are being used for this TAS. This integer will be called 'n'.\n\nThe following 'n' lines are local file paths to the ROMs you wish to use. This will set up an array of cartridges.\n\nThe remaining lines until the end of the file are in the following format: \"x y\" where an integer 'x' is seperated from an integer 'y' with a space.\n\nWhen the TAS is being played back, before CPU cycle 'x', swap to the cartridge at index 'y' into the cartridge array.\n\nHere's an example:\n<pre>\n5\nSuper Mario Bros. [!].nes\nDash Galaxy in the Alien Asylum (U) [!].nes\nKung Fu (JU) [!].nes\nPipe Dream (U) [!].nes\nSuper Mario Bros. 3 (U) (V1.1) [!].nes\n6 0\n7 1\n8 2\n9 3\n10 4\n</pre>\n\nIn this example, there are 5 cartridges. Before cycle 6, the emulator will swap to `Super Mario Bros. [!].nes`, as that is index 0 into the cartridge array. Before cycle 7, the emulator will swap to index 1, `Dash Galaxy in the Alien Asylum (U) [!].nes`, and so on.\n\n# Screenshots\n![Screenshot](https://github.com/user-attachments/assets/56a25c5d-5c2f-493f-85bd-90bb192b1322)\n\n![Screenshot2](https://github.com/user-attachments/assets/5e6771fe-0696-4e27-9fdc-b16fd1b407ef)\n\n![Screenshot3](https://github.com/user-attachments/assets/1689f379-7eb8-445e-9632-81c3a3de2301)\n"
  },
  {
    "path": "TriCNES.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProjectGuid>{B53C8A3B-8F4F-4837-99A0-47D7D9FE757F}</ProjectGuid>\n    <OutputType>WinExe</OutputType>\n    <RootNamespace>TriCNES</RootNamespace>\n    <AssemblyName>TriCNES</AssemblyName>\n    <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>\n    <FileAlignment>512</FileAlignment>\n    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>\n    <Deterministic>true</Deterministic>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <PlatformTarget>AnyCPU</PlatformTarget>\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>bin\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <PlatformTarget>AnyCPU</PlatformTarget>\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>bin\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <PropertyGroup>\n    <ApplicationIcon>icon.ico</ApplicationIcon>\n  </PropertyGroup>\n  <PropertyGroup>\n    <LangVersion>8</LangVersion>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"PresentationCore\" />\n    <Reference Include=\"SDL2-CS, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>packages\\ppy.SDL2-CS.1.0.82\\lib\\netstandard2.0\\SDL2-CS.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"System.IO.Compression\" />\n    <Reference Include=\"System.IO.Compression.FileSystem\" />\n    <Reference Include=\"System.Xml.Linq\" />\n    <Reference Include=\"System.Data.DataSetExtensions\" />\n    <Reference Include=\"Microsoft.CSharp\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Deployment\" />\n    <Reference Include=\"System.Drawing\" />\n    <Reference Include=\"System.Net.Http\" />\n    <Reference Include=\"System.Windows.Forms\" />\n    <Reference Include=\"System.Xml\" />\n    <Reference Include=\"WindowsBase\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"6502Documentation.cs\" />\n    <Compile Include=\"Emulator.cs\" />\n    <Compile Include=\"forms\\TASProperties.cs\">\n      <SubType>Form</SubType>\n    </Compile>\n    <Compile Include=\"forms\\TASProperties.Designer.cs\">\n      <DependentUpon>TASProperties.cs</DependentUpon>\n    </Compile>\n    <Compile Include=\"forms\\TASProperties3ct.cs\">\n      <SubType>Form</SubType>\n    </Compile>\n    <Compile Include=\"forms\\TASProperties3ct.Designer.cs\">\n      <DependentUpon>TASProperties3ct.cs</DependentUpon>\n    </Compile>\n    <Compile Include=\"forms\\TriCHexEditor.cs\">\n      <SubType>Form</SubType>\n    </Compile>\n    <Compile Include=\"forms\\TriCHexEditor.Designer.cs\">\n      <DependentUpon>TriCHexEditor.cs</DependentUpon>\n    </Compile>\n    <Compile Include=\"forms\\TriCNESGUI.cs\">\n      <SubType>Form</SubType>\n    </Compile>\n    <Compile Include=\"forms\\TriCNESGUI.Designer.cs\">\n      <DependentUpon>TriCNESGUI.cs</DependentUpon>\n    </Compile>\n    <Compile Include=\"mappers\\Mapper_NULL.cs\" />\n    <Compile Include=\"mappers\\Mapper_MMC1.cs\" />\n    <Compile Include=\"mappers\\Mapper_MMC3.cs\" />\n    <Compile Include=\"mappers\\Mapper_CNROM.cs\" />\n    <Compile Include=\"mappers\\Mapper_AOROM.cs\" />\n    <Compile Include=\"mappers\\Mapper_MMC2.cs\" />\n    <Compile Include=\"mappers\\Mapper_FME7.cs\" />\n    <Compile Include=\"mappers\\Mapper_FDS.cs\" />\n    <Compile Include=\"mappers\\Mapper_UxROM.cs\" />\n    <Compile Include=\"mappers\\Mapper_NROM.cs\" />\n    <Compile Include=\"Program.cs\" />\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n    <Compile Include=\"forms\\TriCNTViewer.cs\">\n      <SubType>Form</SubType>\n    </Compile>\n    <Compile Include=\"forms\\TriCNTViewer.Designer.cs\">\n      <DependentUpon>TriCNTViewer.cs</DependentUpon>\n    </Compile>\n    <Compile Include=\"forms\\TriCTASTimeline.cs\">\n      <SubType>Form</SubType>\n    </Compile>\n    <Compile Include=\"forms\\TriCTASTimeline.Designer.cs\">\n      <DependentUpon>TriCTASTimeline.cs</DependentUpon>\n    </Compile>\n    <Compile Include=\"forms\\TriCTraceLogger.cs\">\n      <SubType>Form</SubType>\n    </Compile>\n    <Compile Include=\"forms\\TriCTraceLogger.Designer.cs\">\n      <DependentUpon>TriCTraceLogger.cs</DependentUpon>\n    </Compile>\n    <EmbeddedResource Include=\"forms\\TASProperties.resx\">\n      <DependentUpon>TASProperties.cs</DependentUpon>\n    </EmbeddedResource>\n    <EmbeddedResource Include=\"forms\\TASProperties3ct.resx\">\n      <DependentUpon>TASProperties3ct.cs</DependentUpon>\n    </EmbeddedResource>\n    <EmbeddedResource Include=\"forms\\TriCHexEditor.resx\">\n      <DependentUpon>TriCHexEditor.cs</DependentUpon>\n    </EmbeddedResource>\n    <EmbeddedResource Include=\"forms\\TriCNESGUI.resx\">\n      <DependentUpon>TriCNESGUI.cs</DependentUpon>\n    </EmbeddedResource>\n    <EmbeddedResource Include=\"Properties\\Resources.resx\">\n      <Generator>ResXFileCodeGenerator</Generator>\n      <LastGenOutput>Resources.Designer.cs</LastGenOutput>\n      <SubType>Designer</SubType>\n    </EmbeddedResource>\n    <Compile Include=\"Properties\\Resources.Designer.cs\">\n      <AutoGen>True</AutoGen>\n      <DependentUpon>Resources.resx</DependentUpon>\n    </Compile>\n    <EmbeddedResource Include=\"forms\\TriCNTViewer.resx\">\n      <DependentUpon>TriCNTViewer.cs</DependentUpon>\n    </EmbeddedResource>\n    <EmbeddedResource Include=\"forms\\TriCTASTimeline.resx\">\n      <DependentUpon>TriCTASTimeline.cs</DependentUpon>\n    </EmbeddedResource>\n    <EmbeddedResource Include=\"forms\\TriCTraceLogger.resx\">\n      <DependentUpon>TriCTraceLogger.cs</DependentUpon>\n    </EmbeddedResource>\n    <None Include=\"app.config\" />\n    <None Include=\"packages.config\" />\n    <None Include=\"Properties\\Settings.settings\">\n      <Generator>SettingsSingleFileGenerator</Generator>\n      <LastGenOutput>Settings.Designer.cs</LastGenOutput>\n    </None>\n    <Compile Include=\"Properties\\Settings.Designer.cs\">\n      <AutoGen>True</AutoGen>\n      <DependentUpon>Settings.settings</DependentUpon>\n      <DesignTimeSharedInput>True</DesignTimeSharedInput>\n    </Compile>\n  </ItemGroup>\n  <ItemGroup>\n    <WCFMetadata Include=\"Connected Services\\\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Content Include=\"icon.ico\" />\n    <Content Include=\"SDL2.dll\">\n      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\n    </Content>\n  </ItemGroup>\n  <ItemGroup />\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n</Project>"
  },
  {
    "path": "TriCNES.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.10.35013.160\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"TriCNES\", \"TriCNES.csproj\", \"{B53C8A3B-8F4F-4837-99A0-47D7D9FE757F}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Solution Items\", \"Solution Items\", \"{ED419257-E7C5-4EAC-80C7-78320132F3F4}\"\n\tProjectSection(SolutionItems) = preProject\n\t\ticon.ico = icon.ico\n\tEndProjectSection\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{B53C8A3B-8F4F-4837-99A0-47D7D9FE757F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{B53C8A3B-8F4F-4837-99A0-47D7D9FE757F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{B53C8A3B-8F4F-4837-99A0-47D7D9FE757F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{B53C8A3B-8F4F-4837-99A0-47D7D9FE757F}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {0A57AF3A-82C3-46E2-B3C8-8550E13D4B10}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "forms/TASProperties.Designer.cs",
    "content": "﻿namespace TriCNES\n{\n    partial class TASProperties\n    {\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private System.ComponentModel.IContainer components = null;\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        /// <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing && (components != null))\n            {\n                components.Dispose();\n            }\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            this.components = new System.ComponentModel.Container();\n            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TASProperties));\n            this.b_RunTAS = new System.Windows.Forms.Button();\n            this.tb_FilePath = new System.Windows.Forms.TextBox();\n            this.l_FilePath = new System.Windows.Forms.Label();\n            this.rb_LatchFiltering = new System.Windows.Forms.RadioButton();\n            this.rb_ClockFiltering = new System.Windows.Forms.RadioButton();\n            this.panel1 = new System.Windows.Forms.Panel();\n            this.TASPropTooltips = new System.Windows.Forms.ToolTip(this.components);\n            this.cb_ClockAlignment = new System.Windows.Forms.ComboBox();\n            this.cb_CpuClock = new System.Windows.Forms.ComboBox();\n            this.b_BrowseFile = new System.Windows.Forms.Button();\n            this.l_InputCount = new System.Windows.Forms.Label();\n            this.l_FamtasiaWarning = new System.Windows.Forms.Label();\n            this.label3 = new System.Windows.Forms.Label();\n            this.label1 = new System.Windows.Forms.Label();\n            this.cb_fceuxFrame0 = new System.Windows.Forms.CheckBox();\n            this.panel1.SuspendLayout();\n            this.SuspendLayout();\n            // \n            // b_RunTAS\n            // \n            this.b_RunTAS.Anchor = System.Windows.Forms.AnchorStyles.Bottom;\n            this.b_RunTAS.Location = new System.Drawing.Point(24, 255);\n            this.b_RunTAS.Name = \"b_RunTAS\";\n            this.b_RunTAS.Size = new System.Drawing.Size(300, 40);\n            this.b_RunTAS.TabIndex = 0;\n            this.b_RunTAS.Text = \"Run TAS\";\n            this.b_RunTAS.UseVisualStyleBackColor = true;\n            this.b_RunTAS.Click += new System.EventHandler(this.b_RunTAS_Click);\n            // \n            // tb_FilePath\n            // \n            this.tb_FilePath.Anchor = System.Windows.Forms.AnchorStyles.Top;\n            this.tb_FilePath.Location = new System.Drawing.Point(53, 6);\n            this.tb_FilePath.Name = \"tb_FilePath\";\n            this.tb_FilePath.ReadOnly = true;\n            this.tb_FilePath.Size = new System.Drawing.Size(206, 20);\n            this.tb_FilePath.TabIndex = 1;\n            // \n            // l_FilePath\n            // \n            this.l_FilePath.AutoSize = true;\n            this.l_FilePath.Location = new System.Drawing.Point(26, 9);\n            this.l_FilePath.Name = \"l_FilePath\";\n            this.l_FilePath.Size = new System.Drawing.Size(23, 13);\n            this.l_FilePath.TabIndex = 2;\n            this.l_FilePath.Text = \"File\";\n            // \n            // rb_LatchFiltering\n            // \n            this.rb_LatchFiltering.AutoSize = true;\n            this.rb_LatchFiltering.Location = new System.Drawing.Point(5, 3);\n            this.rb_LatchFiltering.Name = \"rb_LatchFiltering\";\n            this.rb_LatchFiltering.Size = new System.Drawing.Size(91, 17);\n            this.rb_LatchFiltering.TabIndex = 3;\n            this.rb_LatchFiltering.TabStop = true;\n            this.rb_LatchFiltering.Text = \"Latch Filtering\";\n            this.TASPropTooltips.SetToolTip(this.rb_LatchFiltering, \"Latch filtering will provide a single input per frame.\");\n            this.rb_LatchFiltering.UseVisualStyleBackColor = true;\n            // \n            // rb_ClockFiltering\n            // \n            this.rb_ClockFiltering.AutoSize = true;\n            this.rb_ClockFiltering.Location = new System.Drawing.Point(5, 26);\n            this.rb_ClockFiltering.Name = \"rb_ClockFiltering\";\n            this.rb_ClockFiltering.Size = new System.Drawing.Size(91, 17);\n            this.rb_ClockFiltering.TabIndex = 4;\n            this.rb_ClockFiltering.TabStop = true;\n            this.rb_ClockFiltering.Text = \"Clock Filtering\";\n            this.TASPropTooltips.SetToolTip(this.rb_ClockFiltering, \"Clock filtering will provide multiple inputs per frame. This is used in \\\"subframe\" +\n        \"\\\" TASes.\");\n            this.rb_ClockFiltering.UseVisualStyleBackColor = true;\n            // \n            // panel1\n            // \n            this.panel1.Controls.Add(this.rb_LatchFiltering);\n            this.panel1.Controls.Add(this.rb_ClockFiltering);\n            this.panel1.Location = new System.Drawing.Point(24, 200);\n            this.panel1.Name = \"panel1\";\n            this.panel1.Size = new System.Drawing.Size(100, 49);\n            this.panel1.TabIndex = 6;\n            // \n            // cb_ClockAlignment\n            // \n            this.cb_ClockAlignment.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.cb_ClockAlignment.FormattingEnabled = true;\n            this.cb_ClockAlignment.Items.AddRange(new object[] {\n            \"Phase 0\",\n            \"Phase 1\",\n            \"Phase 2\",\n            \"Phase 3\"});\n            this.cb_ClockAlignment.Location = new System.Drawing.Point(176, 174);\n            this.cb_ClockAlignment.Name = \"cb_ClockAlignment\";\n            this.cb_ClockAlignment.Size = new System.Drawing.Size(65, 21);\n            this.cb_ClockAlignment.TabIndex = 10;\n            this.TASPropTooltips.SetToolTip(this.cb_ClockAlignment, \"Some runs may desync depending on alignment. Different emulators use different al\" +\n        \"ignments. Only change this if you know what you are doing.\");\n            // \n            // cb_CpuClock\n            // \n            this.cb_CpuClock.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.cb_CpuClock.FormattingEnabled = true;\n            this.cb_CpuClock.Items.AddRange(new object[] {\n            \"Phase 0\",\n            \"Phase 1\",\n            \"Phase 2\",\n            \"Phase 3\",\n            \"Phase 4\",\n            \"Phase 5\",\n            \"Phase 6\",\n            \"Phase 7\",\n            \"Phase 8\",\n            \"Phase 9\",\n            \"Phase 10\",\n            \"Phase 11\"});\n            this.cb_CpuClock.Location = new System.Drawing.Point(176, 151);\n            this.cb_CpuClock.Name = \"cb_CpuClock\";\n            this.cb_CpuClock.Size = new System.Drawing.Size(65, 21);\n            this.cb_CpuClock.TabIndex = 13;\n            this.TASPropTooltips.SetToolTip(this.cb_CpuClock, \"Some runs may desync depending on alignment. Different emulators use different al\" +\n        \"ignments. Only change this if you know what you are doing.\");\n            // \n            // b_BrowseFile\n            // \n            this.b_BrowseFile.Location = new System.Drawing.Point(265, 6);\n            this.b_BrowseFile.Name = \"b_BrowseFile\";\n            this.b_BrowseFile.Size = new System.Drawing.Size(59, 21);\n            this.b_BrowseFile.TabIndex = 7;\n            this.b_BrowseFile.Text = \"Browse...\";\n            this.b_BrowseFile.UseVisualStyleBackColor = true;\n            // \n            // l_InputCount\n            // \n            this.l_InputCount.AutoSize = true;\n            this.l_InputCount.Location = new System.Drawing.Point(26, 29);\n            this.l_InputCount.Name = \"l_InputCount\";\n            this.l_InputCount.Size = new System.Drawing.Size(44, 13);\n            this.l_InputCount.TabIndex = 8;\n            this.l_InputCount.Text = \"0 inputs\";\n            // \n            // l_FamtasiaWarning\n            // \n            this.l_FamtasiaWarning.AutoSize = true;\n            this.l_FamtasiaWarning.Font = new System.Drawing.Font(\"Microsoft Sans Serif\", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.l_FamtasiaWarning.Location = new System.Drawing.Point(12, 73);\n            this.l_FamtasiaWarning.Name = \"l_FamtasiaWarning\";\n            this.l_FamtasiaWarning.Size = new System.Drawing.Size(325, 26);\n            this.l_FamtasiaWarning.TabIndex = 9;\n            this.l_FamtasiaWarning.Text = \"Warning!\\r\\nFamtasia is an old emulator, and the TAS is not guaranteed to sync!\";\n            this.l_FamtasiaWarning.TextAlign = System.Drawing.ContentAlignment.TopCenter;\n            // \n            // label3\n            // \n            this.label3.AutoSize = true;\n            this.label3.Location = new System.Drawing.Point(21, 177);\n            this.label3.Name = \"label3\";\n            this.label3.Size = new System.Drawing.Size(149, 13);\n            this.label3.TabIndex = 11;\n            this.label3.Text = \"PPU / Master clock alignment\";\n            // \n            // label1\n            // \n            this.label1.AutoSize = true;\n            this.label1.Location = new System.Drawing.Point(21, 154);\n            this.label1.Name = \"label1\";\n            this.label1.Size = new System.Drawing.Size(149, 13);\n            this.label1.TabIndex = 12;\n            this.label1.Text = \"CPU / Master clock alignment\";\n            // \n            // cb_fceuxFrame0\n            // \n            this.cb_fceuxFrame0.AutoSize = true;\n            this.cb_fceuxFrame0.Checked = true;\n            this.cb_fceuxFrame0.CheckState = System.Windows.Forms.CheckState.Checked;\n            this.cb_fceuxFrame0.Location = new System.Drawing.Point(24, 124);\n            this.cb_fceuxFrame0.Name = \"cb_fceuxFrame0\";\n            this.cb_fceuxFrame0.Size = new System.Drawing.Size(175, 17);\n            this.cb_fceuxFrame0.TabIndex = 14;\n            this.cb_fceuxFrame0.Text = \"Use FCEUX\\'s Frame 0 behavior\";\n            this.TASPropTooltips.SetToolTip(this.cb_fceuxFrame0, \"FCEUX inaccurately emulates the first frame from the beginning of VBlank rather t\" +\n        \"han the end.\\r\\nUnchecking this box can potentially lead to a desync, though it wi\" +\n        \"ll be more accurate.\");\n            this.cb_fceuxFrame0.UseVisualStyleBackColor = true;\n            // \n            // TASProperties\n            // \n            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);\n            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;\n            this.ClientSize = new System.Drawing.Size(350, 307);\n            this.Controls.Add(this.cb_fceuxFrame0);\n            this.Controls.Add(this.cb_CpuClock);\n            this.Controls.Add(this.label1);\n            this.Controls.Add(this.label3);\n            this.Controls.Add(this.cb_ClockAlignment);\n            this.Controls.Add(this.l_FamtasiaWarning);\n            this.Controls.Add(this.l_InputCount);\n            this.Controls.Add(this.b_BrowseFile);\n            this.Controls.Add(this.panel1);\n            this.Controls.Add(this.l_FilePath);\n            this.Controls.Add(this.tb_FilePath);\n            this.Controls.Add(this.b_RunTAS);\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;\n            this.Icon = ((System.Drawing.Icon)(resources.GetObject(\"$this.Icon\")));\n            this.Name = \"TASProperties\";\n            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;\n            this.Text = \"TAS Properties\";\n            this.panel1.ResumeLayout(false);\n            this.panel1.PerformLayout();\n            this.ResumeLayout(false);\n            this.PerformLayout();\n\n        }\n\n        #endregion\n\n        private System.Windows.Forms.Button b_RunTAS;\n        private System.Windows.Forms.TextBox tb_FilePath;\n        private System.Windows.Forms.Label l_FilePath;\n        private System.Windows.Forms.RadioButton rb_LatchFiltering;\n        private System.Windows.Forms.RadioButton rb_ClockFiltering;\n        private System.Windows.Forms.ToolTip TASPropTooltips;\n        private System.Windows.Forms.Panel panel1;\n        private System.Windows.Forms.Button b_BrowseFile;\n        private System.Windows.Forms.Label l_InputCount;\n        private System.Windows.Forms.Label l_FamtasiaWarning;\n        private System.Windows.Forms.ComboBox cb_ClockAlignment;\n        private System.Windows.Forms.Label label3;\n        private System.Windows.Forms.Label label1;\n        private System.Windows.Forms.ComboBox cb_CpuClock;\n        private System.Windows.Forms.CheckBox cb_fceuxFrame0;\n    }\n}"
  },
  {
    "path": "forms/TASProperties.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Data;\nusing System.Drawing;\nusing System.IO;\nusing System.Linq;\nusing System.Net.NetworkInformation;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.Windows.Forms;\nusing System.IO.Compression;\n\nnamespace TriCNES\n{\n    public partial class TASProperties : Form\n    {\n        public TASProperties()\n        {\n            InitializeComponent();\n        }\n\n        public string TasFilePath;\n        public ushort[] TasInputLog;\n        public bool[] TasResetLog;\n        public TriCNESGUI MainGUI;\n\n        public bool SubframeInputs()\n        {\n            return rb_ClockFiltering.Checked;\n        }\n\n        public bool UseFCEUXFrame0Timing() // this only applies to TASes using the .fm2 or .fm3 file format.\n        {\n            return cb_fceuxFrame0.Checked;\n        }\n\n        public byte GetPPUClockPhase()\n        {\n            return (byte)cb_ClockAlignment.SelectedIndex;\n        }\n\n        public byte GetCPUClockPhase()\n        {\n            return (byte)cb_CpuClock.SelectedIndex;\n        }\n\n        public string extension;\n\n        public void Init()\n        {\n            tb_FilePath.Text = TasFilePath;\n            // determine file type\n            extension = Path.GetExtension(TasFilePath);\n            // create list of inputs from the tas file, and make any settings changes if needed.\n            byte[] ByteArray = File.ReadAllBytes(TasFilePath);\n            List<ushort> TASInputs = new List<ushort>(); // Low byte is player 1, High byte is player 2.\n\n            rb_ClockFiltering.Checked = false;\n            rb_LatchFiltering.Checked = true;\n            l_FamtasiaWarning.Visible = false;\n            cb_ClockAlignment.SelectedIndex = 0;\n            cb_ClockAlignment.Update();\n            cb_CpuClock.SelectedIndex = 0;\n            cb_CpuClock.Update();\n            cb_fceuxFrame0.Enabled = false;\n            switch (extension)\n            {\n                case \".bk2\":\n                case \".tasproj\":\n                    {\n                        cb_CpuClock.SelectedIndex = 8;\n                        cb_CpuClock.Update();\n                    }\n                    break;\n                case \".fm2\":\n                    {\n                        cb_fceuxFrame0.Enabled = true;\n                        // change the alignment to use FCEUX's\n                        cb_CpuClock.SelectedIndex = 0;\n                        cb_CpuClock.Update();\n                    }\n                    break;\n                case \".fm3\":\n                    {\n \n                    }\n                    break;\n                case \".fmv\":\n                    {\n                        l_FamtasiaWarning.Visible = true;\n                    }\n                    break;\n                case \".r08\":\n                    {\n\n                    }\n                    break;\n                case \".3c2\":\n                    {\n\n                    }\n                    break;\n                case \".3c3\":\n                    {\n\n                    }\n                    break;\n\n                    // TODO: ask if the .tasd file format is a thing yet\n            }\n\n            List<bool> Resets = new List<bool>();\n            TASInputs = MainGUI.ParseTasFile(TasFilePath, out Resets);\n            // okay cool, now we have the entire input log.\n            TasInputLog = TASInputs.ToArray();\n            TasResetLog = Resets.ToArray();\n            l_InputCount.Text = TasInputLog.Length + \" Inputs\";\n        }\n\n        private void b_RunTAS_Click(object sender, EventArgs e)\n        {\n            MainGUI.StartTAS();\n\n\n        }\n    }\n}\n"
  },
  {
    "path": "forms/TASProperties.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <metadata name=\"TASPropTooltips.TrayLocation\" type=\"System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n    <value>17, 17</value>\n  </metadata>\n  <assembly alias=\"System.Drawing\" name=\"System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\" />\n  <data name=\"$this.Icon\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAA/wAA\n        AP8AAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAA\n        AP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA\n        AAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAA\n        AP8AAAD/AAAA/wAAAP8AAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAAAAAA\n        AAD///////////////////////////////8AAAAAAAAAAAAAAP8AAAD/AAAAAAAAAAD/////////////\n        //////////////////8AAAAAAAAAAAAAAP8AAAD/////////////////////////////////AAAAAAAA\n        AAAAAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//\n        /////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAA\n        AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////\n        ////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA////////\n        //8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAA\n        AP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAA\n        AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//\n        ////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAA\n        AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAA\n        AAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA////////\n        //8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA\n        AAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA\n        AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAA\n        AP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAA\n        AAAAAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//\n        ////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAA\n        AP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA\n        AAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/////////\n        //8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD//////////////////////wAA\n        AP8AAAD/AAAAAAAAAAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAA\n        AAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAAAAD/////////////\n        ////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/////////\n        //8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD///////////8AAAAAAAAAAAAA\n        AAAAAAAA//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////\n        //8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////////8AAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////////\n        /////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////////////////////////wAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAA///////////////////////////////////////////A8D8DwPA/AwPA\n        zAwDwMwMww8A8MMPAPDDDwDwww8A8MMPAPDDDwDwww8A8MMPAPADMDMDAzAzA8/A/A/PwPwP////////\n        //////////////////////////////////8=\n</value>\n  </data>\n</root>"
  },
  {
    "path": "forms/TASProperties3ct.Designer.cs",
    "content": "﻿namespace TriCNES\n{\n    partial class TASProperties3ct\n    {\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private System.ComponentModel.IContainer components = null;\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        /// <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing && (components != null))\n            {\n                components.Dispose();\n            }\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TASProperties3ct));\n            this.cb_CpuClock = new System.Windows.Forms.ComboBox();\n            this.label1 = new System.Windows.Forms.Label();\n            this.label3 = new System.Windows.Forms.Label();\n            this.cb_ClockAlignment = new System.Windows.Forms.ComboBox();\n            this.l_InputCount = new System.Windows.Forms.Label();\n            this.b_BrowseFile = new System.Windows.Forms.Button();\n            this.l_FilePath = new System.Windows.Forms.Label();\n            this.tb_FilePath = new System.Windows.Forms.TextBox();\n            this.b_RunTAS = new System.Windows.Forms.Button();\n            this.b_LoadCartridges = new System.Windows.Forms.Button();\n            this.panel1 = new System.Windows.Forms.Panel();\n            this.rb_FromPOW = new System.Windows.Forms.RadioButton();\n            this.rb_FromRES = new System.Windows.Forms.RadioButton();\n            this.panel1.SuspendLayout();\n            this.SuspendLayout();\n            // \n            // cb_CpuClock\n            // \n            this.cb_CpuClock.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.cb_CpuClock.FormattingEnabled = true;\n            this.cb_CpuClock.Items.AddRange(new object[] {\n            \"Phase 0\",\n            \"Phase 1\",\n            \"Phase 2\",\n            \"Phase 3\",\n            \"Phase 4\",\n            \"Phase 5\",\n            \"Phase 6\",\n            \"Phase 7\",\n            \"Phase 8\",\n            \"Phase 9\",\n            \"Phase 10\",\n            \"Phase 11\"});\n            this.cb_CpuClock.Location = new System.Drawing.Point(177, 56);\n            this.cb_CpuClock.Name = \"cb_CpuClock\";\n            this.cb_CpuClock.Size = new System.Drawing.Size(65, 21);\n            this.cb_CpuClock.TabIndex = 24;\n            // \n            // label1\n            // \n            this.label1.AutoSize = true;\n            this.label1.Location = new System.Drawing.Point(22, 59);\n            this.label1.Name = \"label1\";\n            this.label1.Size = new System.Drawing.Size(149, 13);\n            this.label1.TabIndex = 23;\n            this.label1.Text = \"CPU / Master clock alignment\";\n            // \n            // label3\n            // \n            this.label3.AutoSize = true;\n            this.label3.Location = new System.Drawing.Point(22, 82);\n            this.label3.Name = \"label3\";\n            this.label3.Size = new System.Drawing.Size(149, 13);\n            this.label3.TabIndex = 22;\n            this.label3.Text = \"PPU / Master clock alignment\";\n            // \n            // cb_ClockAlignment\n            // \n            this.cb_ClockAlignment.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;\n            this.cb_ClockAlignment.FormattingEnabled = true;\n            this.cb_ClockAlignment.Items.AddRange(new object[] {\n            \"Phase 0\",\n            \"Phase 1\",\n            \"Phase 2\",\n            \"Phase 3\"});\n            this.cb_ClockAlignment.Location = new System.Drawing.Point(177, 79);\n            this.cb_ClockAlignment.Name = \"cb_ClockAlignment\";\n            this.cb_ClockAlignment.Size = new System.Drawing.Size(65, 21);\n            this.cb_ClockAlignment.TabIndex = 21;\n            // \n            // l_InputCount\n            // \n            this.l_InputCount.AutoSize = true;\n            this.l_InputCount.Location = new System.Drawing.Point(27, 32);\n            this.l_InputCount.Name = \"l_InputCount\";\n            this.l_InputCount.Size = new System.Drawing.Size(44, 13);\n            this.l_InputCount.TabIndex = 19;\n            this.l_InputCount.Text = \"0 inputs\";\n            // \n            // b_BrowseFile\n            // \n            this.b_BrowseFile.Location = new System.Drawing.Point(266, 9);\n            this.b_BrowseFile.Name = \"b_BrowseFile\";\n            this.b_BrowseFile.Size = new System.Drawing.Size(59, 21);\n            this.b_BrowseFile.TabIndex = 18;\n            this.b_BrowseFile.Text = \"Browse...\";\n            this.b_BrowseFile.UseVisualStyleBackColor = true;\n            // \n            // l_FilePath\n            // \n            this.l_FilePath.AutoSize = true;\n            this.l_FilePath.Location = new System.Drawing.Point(27, 12);\n            this.l_FilePath.Name = \"l_FilePath\";\n            this.l_FilePath.Size = new System.Drawing.Size(23, 13);\n            this.l_FilePath.TabIndex = 16;\n            this.l_FilePath.Text = \"File\";\n            // \n            // tb_FilePath\n            // \n            this.tb_FilePath.Anchor = System.Windows.Forms.AnchorStyles.Top;\n            this.tb_FilePath.Location = new System.Drawing.Point(54, 9);\n            this.tb_FilePath.Name = \"tb_FilePath\";\n            this.tb_FilePath.ReadOnly = true;\n            this.tb_FilePath.Size = new System.Drawing.Size(206, 20);\n            this.tb_FilePath.TabIndex = 15;\n            // \n            // b_RunTAS\n            // \n            this.b_RunTAS.Anchor = System.Windows.Forms.AnchorStyles.Bottom;\n            this.b_RunTAS.Enabled = false;\n            this.b_RunTAS.Location = new System.Drawing.Point(25, 212);\n            this.b_RunTAS.Name = \"b_RunTAS\";\n            this.b_RunTAS.Size = new System.Drawing.Size(300, 40);\n            this.b_RunTAS.TabIndex = 14;\n            this.b_RunTAS.Text = \"Run TAS\";\n            this.b_RunTAS.UseVisualStyleBackColor = true;\n            this.b_RunTAS.Click += new System.EventHandler(this.b_RunTAS_Click);\n            // \n            // b_LoadCartridges\n            // \n            this.b_LoadCartridges.Anchor = System.Windows.Forms.AnchorStyles.Bottom;\n            this.b_LoadCartridges.Location = new System.Drawing.Point(25, 154);\n            this.b_LoadCartridges.Name = \"b_LoadCartridges\";\n            this.b_LoadCartridges.Size = new System.Drawing.Size(300, 40);\n            this.b_LoadCartridges.TabIndex = 25;\n            this.b_LoadCartridges.Text = \"Load Cartridges\";\n            this.b_LoadCartridges.UseVisualStyleBackColor = true;\n            this.b_LoadCartridges.Click += new System.EventHandler(this.b_LoadCartridges_Click);\n            // \n            // panel1\n            // \n            this.panel1.Controls.Add(this.rb_FromPOW);\n            this.panel1.Controls.Add(this.rb_FromRES);\n            this.panel1.Location = new System.Drawing.Point(25, 98);\n            this.panel1.Name = \"panel1\";\n            this.panel1.Size = new System.Drawing.Size(100, 49);\n            this.panel1.TabIndex = 26;\n            // \n            // rb_FromPOW\n            // \n            this.rb_FromPOW.AutoSize = true;\n            this.rb_FromPOW.Location = new System.Drawing.Point(5, 3);\n            this.rb_FromPOW.Name = \"rb_FromPOW\";\n            this.rb_FromPOW.Size = new System.Drawing.Size(92, 17);\n            this.rb_FromPOW.TabIndex = 3;\n            this.rb_FromPOW.TabStop = true;\n            this.rb_FromPOW.Text = \"From POWER\";\n            this.rb_FromPOW.UseVisualStyleBackColor = true;\n            // \n            // rb_FromRES\n            // \n            this.rb_FromRES.AutoSize = true;\n            this.rb_FromRES.Location = new System.Drawing.Point(5, 26);\n            this.rb_FromRES.Name = \"rb_FromRES\";\n            this.rb_FromRES.Size = new System.Drawing.Size(87, 17);\n            this.rb_FromRES.TabIndex = 4;\n            this.rb_FromRES.TabStop = true;\n            this.rb_FromRES.Text = \"From RESET\";\n            this.rb_FromRES.UseVisualStyleBackColor = true;\n            // \n            // TASProperties3ct\n            // \n            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);\n            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;\n            this.ClientSize = new System.Drawing.Size(350, 264);\n            this.Controls.Add(this.panel1);\n            this.Controls.Add(this.b_LoadCartridges);\n            this.Controls.Add(this.cb_CpuClock);\n            this.Controls.Add(this.label1);\n            this.Controls.Add(this.label3);\n            this.Controls.Add(this.cb_ClockAlignment);\n            this.Controls.Add(this.l_InputCount);\n            this.Controls.Add(this.b_BrowseFile);\n            this.Controls.Add(this.l_FilePath);\n            this.Controls.Add(this.tb_FilePath);\n            this.Controls.Add(this.b_RunTAS);\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;\n            this.Icon = ((System.Drawing.Icon)(resources.GetObject(\"$this.Icon\")));\n            this.Name = \"TASProperties3ct\";\n            this.Text = \"3CT TAS Properties\";\n            this.panel1.ResumeLayout(false);\n            this.panel1.PerformLayout();\n            this.ResumeLayout(false);\n            this.PerformLayout();\n\n        }\n\n        #endregion\n\n        private System.Windows.Forms.ComboBox cb_CpuClock;\n        private System.Windows.Forms.Label label1;\n        private System.Windows.Forms.Label label3;\n        private System.Windows.Forms.ComboBox cb_ClockAlignment;\n        private System.Windows.Forms.Label l_InputCount;\n        private System.Windows.Forms.Button b_BrowseFile;\n        private System.Windows.Forms.Label l_FilePath;\n        private System.Windows.Forms.TextBox tb_FilePath;\n        private System.Windows.Forms.Button b_RunTAS;\n        private System.Windows.Forms.Button b_LoadCartridges;\n        private System.Windows.Forms.Panel panel1;\n        private System.Windows.Forms.RadioButton rb_FromPOW;\n        private System.Windows.Forms.RadioButton rb_FromRES;\n    }\n}"
  },
  {
    "path": "forms/TASProperties3ct.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Data;\nusing System.Drawing;\nusing System.IO;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.Windows.Forms;\nusing TriCNES.mappers;\n\nnamespace TriCNES\n{\n    public partial class TASProperties3ct : Form\n    {\n        public TASProperties3ct()\n        {\n            InitializeComponent();\n        }\n\n        public string TasFilePath;\n        public ushort[] TasInputLog;\n        public TriCNESGUI MainGUI;\n\n        public byte GetPPUClockPhase()\n        {\n            return (byte)cb_ClockAlignment.SelectedIndex;\n        }\n\n        public byte GetCPUClockPhase()\n        {\n            return (byte)cb_CpuClock.SelectedIndex;\n        }\n\n        public bool FromRESET()\n        {\n            return rb_FromRES.Checked;\n        }\n\n        public Cartridge[] CartridgeArray;\n\n        public void Init()\n        {\n            tb_FilePath.Text = TasFilePath;\n            cb_ClockAlignment.SelectedIndex = 0;\n            cb_ClockAlignment.Update();\n            cb_CpuClock.SelectedIndex = 0;\n            cb_CpuClock.Update();\n            rb_FromPOW.Checked = true;\n            rb_FromPOW.Update();\n        }\n\n        Cartridge BackupCart;\n\n        private void b_RunTAS_Click(object sender, EventArgs e)\n        {\n            if (rb_FromPOW.Checked)\n            {\n                int i = 0;\n                while (i < CartridgeArray.Length)\n                {\n                    CartridgeArray[i].PRGRAM = new byte[0x2000];\n                    CartridgeArray[i].CHRRAM = new byte[0x2000];\n                    Mapper MapperChip;\n                    // clear all mapper stuff.\n                    switch (CartridgeArray[i].MemoryMapper)\n                    {\n                        default:\n                        case 0: MapperChip = new Mapper_NROM(); break;\n                        case 1: MapperChip = new Mapper_MMC1(); break;\n                        case 2: MapperChip = new Mapper_UxROM(); break;\n                        case 3: MapperChip = new Mapper_CNROM(); break;\n                        case 4: MapperChip = new Mapper_MMC3(); break;\n                        case 7: MapperChip = new Mapper_AOROM(); break;\n                        case 9: MapperChip = new Mapper_MMC2(); break;\n                        case 69: MapperChip = new Mapper_FME7(); break;\n                    }\n                    MapperChip.Cart = CartridgeArray[i];\n                    CartridgeArray[i].MapperChip = MapperChip;\n                    i++;\n                }\n            }\n            MainGUI.Start3CTTAS();\n        }\n\n        public List<int> CyclesToSwapOn;\n        public List<int> CartsToSwapIn;\n        private void b_LoadCartridges_Click(object sender, EventArgs e)\n        {\n            bool error = false;\n            // check if rom folder is empty\n            string Dir = AppDomain.CurrentDomain.BaseDirectory;\n            if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @\"roms\\\"))\n            {\n                Dir += @\"roms\\\";\n                if(Directory.GetFiles(Dir).Length == 0)\n                {\n                    MessageBox.Show(\"Loading a .3ct TAS requires your roms to be located in the TriCNES roms folder.\");\n                    return;\n                }\n            }\n            // rom folder isn't empty!\n\n            StringReader SR = new StringReader(File.ReadAllText(tb_FilePath.Text));\n            string l = SR.ReadLine();\n            int count = int.Parse(l);\n            CartridgeArray = new Cartridge[count];\n            int i = 0;\n            while(i < count)\n            {\n                l = SR.ReadLine();\n                if(File.Exists(Dir+l))\n                {\n                    if(i ==0)\n                    {\n                        BackupCart = new Cartridge(Dir + l);\n                    }\n                    if (MainGUI.EMU != null && MainGUI.EMU.Cart.Name == (Dir + l))\n                    {\n                        CartridgeArray[i] = MainGUI.EMU.Cart; // If running a TAS from RESET, we want to use the currently loaded cartridge\n                    }\n                    else\n                    {\n                        CartridgeArray[i] = new Cartridge(Dir + l);\n                    }\n                }\n                else\n                {\n                    MessageBox.Show(\"TriCNES roms folder is missing a required ROM for this TAS!\\n\\nMissing ROM: \\\"\" + l + \"\\\"\");\n                    return;\n                }\n                i++;\n            }\n            // if all carts are now loaded.\n            // let's also prepare the cycles to swap on, and the carts to swap in\n            CyclesToSwapOn = new List<int>();\n            CartsToSwapIn = new List<int>();\n\n            l = SR.ReadLine();\n            while (l != null)\n            {\n                // the format here is:\n                //x y\n                //x and y could be any length, but there's a space between them.\n\n                string s = l.Substring(0, l.IndexOf(\" \"));\n                CyclesToSwapOn.Add(int.Parse(s));\n                s = l.Remove(0,s.Length+1);\n                CartsToSwapIn.Add(int.Parse(s));\n                l = SR.ReadLine();\n            }\n\n\n            b_RunTAS.Enabled = true;\n        }\n\n    }\n}\n"
  },
  {
    "path": "forms/TASProperties3ct.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <assembly alias=\"System.Drawing\" name=\"System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\" />\n  <data name=\"$this.Icon\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAA/wAA\n        AP8AAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAA\n        AP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA\n        AAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAA\n        AP8AAAD/AAAA/wAAAP8AAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAAAAAA\n        AAD///////////////////////////////8AAAAAAAAAAAAAAP8AAAD/AAAAAAAAAAD/////////////\n        //////////////////8AAAAAAAAAAAAAAP8AAAD/////////////////////////////////AAAAAAAA\n        AAAAAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//\n        /////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAA\n        AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////\n        ////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA////////\n        //8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAA\n        AP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAA\n        AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//\n        ////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAA\n        AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAA\n        AAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA////////\n        //8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA\n        AAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA\n        AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAA\n        AP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAA\n        AAAAAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//\n        ////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAA\n        AP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA\n        AAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/////////\n        //8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD//////////////////////wAA\n        AP8AAAD/AAAAAAAAAAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAA\n        AAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAAAAD/////////////\n        ////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/////////\n        //8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD///////////8AAAAAAAAAAAAA\n        AAAAAAAA//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////\n        //8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////////8AAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////////\n        /////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////////////////////////wAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAA///////////////////////////////////////////A8D8DwPA/AwPA\n        zAwDwMwMww8A8MMPAPDDDwDwww8A8MMPAPDDDwDwww8A8MMPAPADMDMDAzAzA8/A/A/PwPwP////////\n        //////////////////////////////////8=\n</value>\n  </data>\n</root>"
  },
  {
    "path": "forms/TriCHexEditor.Designer.cs",
    "content": "﻿namespace TriCNES\n{\n    partial class TriCHexEditor\n    {\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private System.ComponentModel.IContainer components = null;\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        /// <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing && (components != null))\n            {\n                components.Dispose();\n            }\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TriCHexEditor));\n            this.pb_hexView = new System.Windows.Forms.PictureBox();\n            this.vScrollBar1 = new System.Windows.Forms.VScrollBar();\n            this.menuStrip1 = new System.Windows.Forms.MenuStrip();\n            this.settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.scopeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.rAMToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.cPUAddressSpaceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.vRAMToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.pPUAddressSpaceToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.oAMToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.paletteRAMToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.copyToClipboardToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            ((System.ComponentModel.ISupportInitialize)(this.pb_hexView)).BeginInit();\n            this.menuStrip1.SuspendLayout();\n            this.SuspendLayout();\n            // \n            // pb_hexView\n            // \n            this.pb_hexView.Location = new System.Drawing.Point(12, 37);\n            this.pb_hexView.Name = \"pb_hexView\";\n            this.pb_hexView.Size = new System.Drawing.Size(312, 512);\n            this.pb_hexView.TabIndex = 0;\n            this.pb_hexView.TabStop = false;\n            // \n            // vScrollBar1\n            // \n            this.vScrollBar1.LargeChange = 32;\n            this.vScrollBar1.Location = new System.Drawing.Point(327, 57);\n            this.vScrollBar1.Maximum = 128;\n            this.vScrollBar1.Name = \"vScrollBar1\";\n            this.vScrollBar1.Size = new System.Drawing.Size(17, 492);\n            this.vScrollBar1.TabIndex = 1;\n            // \n            // menuStrip1\n            // \n            this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {\n            this.fileToolStripMenuItem,\n            this.settingsToolStripMenuItem});\n            this.menuStrip1.Location = new System.Drawing.Point(0, 0);\n            this.menuStrip1.Name = \"menuStrip1\";\n            this.menuStrip1.Size = new System.Drawing.Size(356, 24);\n            this.menuStrip1.TabIndex = 2;\n            this.menuStrip1.Text = \"menuStrip1\";\n            // \n            // settingsToolStripMenuItem\n            // \n            this.settingsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {\n            this.scopeToolStripMenuItem});\n            this.settingsToolStripMenuItem.Name = \"settingsToolStripMenuItem\";\n            this.settingsToolStripMenuItem.Size = new System.Drawing.Size(61, 20);\n            this.settingsToolStripMenuItem.Text = \"Settings\";\n            // \n            // scopeToolStripMenuItem\n            // \n            this.scopeToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {\n            this.rAMToolStripMenuItem,\n            this.cPUAddressSpaceToolStripMenuItem,\n            this.vRAMToolStripMenuItem,\n            this.pPUAddressSpaceToolStripMenuItem,\n            this.oAMToolStripMenuItem,\n            this.paletteRAMToolStripMenuItem});\n            this.scopeToolStripMenuItem.Name = \"scopeToolStripMenuItem\";\n            this.scopeToolStripMenuItem.Size = new System.Drawing.Size(180, 22);\n            this.scopeToolStripMenuItem.Text = \"Scope\";\n            // \n            // rAMToolStripMenuItem\n            // \n            this.rAMToolStripMenuItem.Checked = true;\n            this.rAMToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;\n            this.rAMToolStripMenuItem.Name = \"rAMToolStripMenuItem\";\n            this.rAMToolStripMenuItem.Size = new System.Drawing.Size(176, 22);\n            this.rAMToolStripMenuItem.Text = \"RAM\";\n            this.rAMToolStripMenuItem.Click += new System.EventHandler(this.rAMToolStripMenuItem_Click);\n            // \n            // cPUAddressSpaceToolStripMenuItem\n            // \n            this.cPUAddressSpaceToolStripMenuItem.Name = \"cPUAddressSpaceToolStripMenuItem\";\n            this.cPUAddressSpaceToolStripMenuItem.Size = new System.Drawing.Size(176, 22);\n            this.cPUAddressSpaceToolStripMenuItem.Text = \"CPU Address Space\";\n            this.cPUAddressSpaceToolStripMenuItem.Click += new System.EventHandler(this.cPUAddressSpaceToolStripMenuItem_Click);\n            // \n            // vRAMToolStripMenuItem\n            // \n            this.vRAMToolStripMenuItem.Name = \"vRAMToolStripMenuItem\";\n            this.vRAMToolStripMenuItem.Size = new System.Drawing.Size(176, 22);\n            this.vRAMToolStripMenuItem.Text = \"VRAM\";\n            this.vRAMToolStripMenuItem.Click += new System.EventHandler(this.vRAMToolStripMenuItem_Click);\n            // \n            // pPUAddressSpaceToolStripMenuItem\n            // \n            this.pPUAddressSpaceToolStripMenuItem.Name = \"pPUAddressSpaceToolStripMenuItem\";\n            this.pPUAddressSpaceToolStripMenuItem.Size = new System.Drawing.Size(176, 22);\n            this.pPUAddressSpaceToolStripMenuItem.Text = \"PPU Address Space\";\n            this.pPUAddressSpaceToolStripMenuItem.Click += new System.EventHandler(this.pPUAddressSpaceToolStripMenuItem_Click);\n            // \n            // oAMToolStripMenuItem\n            // \n            this.oAMToolStripMenuItem.Name = \"oAMToolStripMenuItem\";\n            this.oAMToolStripMenuItem.Size = new System.Drawing.Size(176, 22);\n            this.oAMToolStripMenuItem.Text = \"OAM\";\n            this.oAMToolStripMenuItem.Click += new System.EventHandler(this.oAMToolStripMenuItem_Click);\n            // \n            // paletteRAMToolStripMenuItem\n            // \n            this.paletteRAMToolStripMenuItem.Name = \"paletteRAMToolStripMenuItem\";\n            this.paletteRAMToolStripMenuItem.Size = new System.Drawing.Size(176, 22);\n            this.paletteRAMToolStripMenuItem.Text = \"Palette RAM\";\n            this.paletteRAMToolStripMenuItem.Click += new System.EventHandler(this.paletteRAMToolStripMenuItem_Click);\n            // \n            // fileToolStripMenuItem\n            // \n            this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {\n            this.copyToClipboardToolStripMenuItem});\n            this.fileToolStripMenuItem.Name = \"fileToolStripMenuItem\";\n            this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20);\n            this.fileToolStripMenuItem.Text = \"File\";\n            // \n            // copyToClipboardToolStripMenuItem\n            // \n            this.copyToClipboardToolStripMenuItem.Name = \"copyToClipboardToolStripMenuItem\";\n            this.copyToClipboardToolStripMenuItem.Size = new System.Drawing.Size(180, 22);\n            this.copyToClipboardToolStripMenuItem.Text = \"Copy to Clipboard\";\n            this.copyToClipboardToolStripMenuItem.Click += new System.EventHandler(this.copyToClipboardToolStripMenuItem_Click);\n            // \n            // TriCHexEditor\n            // \n            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);\n            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;\n            this.ClientSize = new System.Drawing.Size(356, 561);\n            this.Controls.Add(this.vScrollBar1);\n            this.Controls.Add(this.pb_hexView);\n            this.Controls.Add(this.menuStrip1);\n            this.Icon = ((System.Drawing.Icon)(resources.GetObject(\"$this.Icon\")));\n            this.MainMenuStrip = this.menuStrip1;\n            this.MinimumSize = new System.Drawing.Size(16, 135);\n            this.Name = \"TriCHexEditor\";\n            this.Text = \"Hex Editor\";\n            ((System.ComponentModel.ISupportInitialize)(this.pb_hexView)).EndInit();\n            this.menuStrip1.ResumeLayout(false);\n            this.menuStrip1.PerformLayout();\n            this.ResumeLayout(false);\n            this.PerformLayout();\n\n        }\n\n        #endregion\n\n        private System.Windows.Forms.PictureBox pb_hexView;\n        private System.Windows.Forms.VScrollBar vScrollBar1;\n        private System.Windows.Forms.MenuStrip menuStrip1;\n        private System.Windows.Forms.ToolStripMenuItem settingsToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem scopeToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem rAMToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem cPUAddressSpaceToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem vRAMToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem pPUAddressSpaceToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem oAMToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem paletteRAMToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem copyToClipboardToolStripMenuItem;\n    }\n}"
  },
  {
    "path": "forms/TriCHexEditor.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Data;\nusing System.Drawing;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.Windows.Forms;\nusing static System.Windows.Forms.VisualStyles.VisualStyleElement;\n\nnamespace TriCNES\n{\n    public partial class TriCHexEditor : Form\n    {\n        public TriCHexEditor()\n        {\n            InitializeComponent();\n            hexBitmap = new Bitmap(312,512);\n            G = Graphics.FromImage(hexBitmap);\n            Font_Consolas = new Font(\"Consolas\", 8);\n            Scope = \"RAM\";\n            Resize += TriCHexEditor_Resize;\n            vScrollBar1.ValueChanged += Scrollbar_ValueChanged;\n        }\n\n        public TriCNESGUI MainGUI;\n        public Graphics G;\n        public Bitmap hexBitmap;\n        public Font Font_Consolas;\n        public int Scroll;\n        public string Scope;\n        ScopeType scopeType = ScopeType.RAM;\n\n        public int MaxRows = 32;\n\n        private void TriCHexEditor_Resize(object sender, EventArgs e)\n        {\n            MaxRows = (Size.Height - 115) / 15;\n            hexBitmap = new Bitmap(312, Size.Height - 88);\n            pb_hexView.Size = new Size(312, Size.Height - 88);\n            vScrollBar1.Size = new Size(vScrollBar1.Width,Size.Height-108);\n            vScrollBar1.LargeChange = MaxRows;\n            G = Graphics.FromImage(hexBitmap);\n            RefreshEntireHexView();\n        }\n\n        private void Scrollbar_ValueChanged(object sender, EventArgs e)\n        {\n            Scroll = vScrollBar1.Value;\n            RefreshEntireHexView();\n        }\n\n        enum ScopeType\n        {\n            RAM,\n            CPU_Address_Space,\n            VRAM,\n            PPU_Address_Space,\n            OAM,\n            Palette_RAM\n        };\n\n        public void Update()\n        {\n            MethodInvoker upd = delegate\n            {\n                RefreshEntireHexView();\n            };\n            try\n            {\n                this.Invoke(upd);\n            }\n            catch(Exception e)\n            {\n\n            }\n        }\n\n        public void RefreshEntireHexView()\n        {\n            if(MainGUI.EMU == null)\n            {\n                return;\n            }\n\n            vScrollBar1.Enabled = MaxRows < vScrollBar1.Maximum;\n            vScrollBar1.Update();\n\n            G.FillRectangle(Brushes.WhiteSmoke,new Rectangle(0,0, 312, Size.Height - 88));\n            G.DrawString(Scope + \":\", Font_Consolas, Brushes.Black, new Point(0, 0));\n            for (int x = 0; x < 0x10; x++)\n            {\n                G.DrawString(\" \" + x.ToString(\"X\"), Font_Consolas, Brushes.Black, new Point(42 + x * 15, 16));\n            }\n            switch (scopeType)\n            {\n                case ScopeType.RAM:\n                    {\n                        int i = Scroll*0x10;\n                        int y = 0;\n                        while(i < 0x800 && y < MaxRows)\n                        {\n                            // print $xy0:\n                            G.DrawString(\"$\" + (i).ToString(\"X3\") + \":\", Font_Consolas, Brushes.Black, new Point(0, 32+y*15));\n                            for(int x=0; x < 0x10; x++)\n                            {\n                                G.DrawString(MainGUI.EMU.RAM[i].ToString(\"X2\"), Font_Consolas, Brushes.Black, new Point(42 + x*15, 32 + y * 15));\n                                i++;\n                            }\n                            y++;\n                        }\n                    }\n                    break;\n                case ScopeType.CPU_Address_Space:\n                    {\n                        int i = Scroll * 0x10;\n                        int y = 0;\n                        while (i < 0x10000 && y < MaxRows)\n                        {\n                            // print $xyz0:\n                            G.DrawString(\"$\" + (i).ToString(\"X4\") + \":\", Font_Consolas, Brushes.Black, new Point(0, 32 + y * 15));\n\n                            for (int x = 0; x < 0x10; x++)\n                            {\n                                G.DrawString(MainGUI.EMU.Observe((ushort)i).ToString(\"X2\"), Font_Consolas, Brushes.Black, new Point(42 + x * 15, 32 + y * 15));\n                                i++;\n                            }\n                            y++;\n                        }\n                    }\n                    break;\n                case ScopeType.VRAM:\n                    {\n                        int i = Scroll * 0x10;\n                        int y = 0;\n                        while (i < 0x800 && y < MaxRows)\n                        {\n                            // print $xy0:\n                            G.DrawString(\"$\" + (i).ToString(\"X3\") + \":\", Font_Consolas, Brushes.Black, new Point(0, 32 + y * 15));\n                            for (int x = 0; x < 0x10; x++)\n                            {\n                                G.DrawString(MainGUI.EMU.VRAM[i].ToString(\"X2\"), Font_Consolas, Brushes.Black, new Point(42 + x * 15, 32 + y * 15));\n                                i++;\n                            }\n                            y++;\n                        }\n                    }\n                    break;\n                case ScopeType.PPU_Address_Space:\n                    {\n                        int i = Scroll * 0x10;\n                        int y = 0;\n                        while (i < 0x4000 && y < MaxRows)\n                        {\n                            // print $xyz0:\n                            G.DrawString(\"$\" + (i).ToString(\"X4\") + \":\", Font_Consolas, Brushes.Black, new Point(0, 32 + y * 15));\n\n                            for (int x = 0; x < 0x10; x++)\n                            {\n                                G.DrawString(MainGUI.EMU.ObservePPU((ushort)i).ToString(\"X2\"), Font_Consolas, Brushes.Black, new Point(42 + x * 15, 32 + y * 15));\n                                i++;\n                            }\n                            y++;\n                        }\n                    }\n                    break;\n                case ScopeType.OAM:\n                    {\n                        int i = Scroll * 0x10;\n                        int y = 0;\n                        while (i < 0x100 && y < MaxRows)\n                        {\n                            // print $xy0:\n                            G.DrawString(\"$\" + (i).ToString(\"X3\") + \":\", Font_Consolas, Brushes.Black, new Point(0, 32 + y * 15));\n                            for (int x = 0; x < 0x10; x++)\n                            {\n                                G.DrawString(MainGUI.EMU.OAM[i].ToString(\"X2\"), Font_Consolas, Brushes.Black, new Point(42 + x * 15, 32 + y * 15));\n                                i++;\n                            }\n                            y++;\n                        }\n                    }\n                    break;\n                case ScopeType.Palette_RAM:\n                    {\n                        int i = Scroll * 0x10;\n                        int y = 0;\n                        while (i < 0x20 && y < MaxRows)\n                        {\n                            // print $xy0:\n                            G.DrawString(\"$\" + (i).ToString(\"X3\") + \":\", Font_Consolas, Brushes.Black, new Point(0, 32 + y * 15));\n                            for (int x = 0; x < 0x10; x++)\n                            {\n                                G.DrawString(MainGUI.EMU.PaletteRAM[i].ToString(\"X2\"), Font_Consolas, Brushes.Black, new Point(42 + x * 15, 32 + y * 15));\n                                i++;\n                            }\n                            y++;\n                        }\n                    }\n                    break;\n            }\n\n            pb_hexView.Image = hexBitmap;\n            pb_hexView.Update();\n        }\n\n        void ChangeScope(ScopeType st)\n        {\n            Scroll = 0;\n            vScrollBar1.Value = 0;\n            vScrollBar1.Update();\n            rAMToolStripMenuItem.Checked = st == ScopeType.RAM;\n            cPUAddressSpaceToolStripMenuItem.Checked = st == ScopeType.CPU_Address_Space;\n            vRAMToolStripMenuItem.Checked = st == ScopeType.VRAM;\n            pPUAddressSpaceToolStripMenuItem.Checked = st == ScopeType.PPU_Address_Space;\n            oAMToolStripMenuItem.Checked = st == ScopeType.OAM;\n            paletteRAMToolStripMenuItem.Checked = st == ScopeType.Palette_RAM;\n            scopeType = st;\n            switch(st)\n            {\n                case ScopeType.RAM:\n                    vScrollBar1.Maximum = 0x80; Scope = \"RAM\"; break;\n                case ScopeType.CPU_Address_Space:\n                    vScrollBar1.Maximum = 0x1000; Scope = \"CPU Address Space\"; break;\n                case ScopeType.VRAM:\n                    vScrollBar1.Maximum = 0x80; Scope = \"VRAM\"; break;\n                case ScopeType.PPU_Address_Space:\n                    vScrollBar1.Maximum = 0x400; Scope = \"PPU Address Space\"; break;\n                case ScopeType.OAM:\n                    vScrollBar1.Maximum = 0x10; Scope = \"OAM\"; break;\n                case ScopeType.Palette_RAM:\n                    vScrollBar1.Maximum = 0x2; Scope = \"Palette RAM\"; break;\n            }\n            RefreshEntireHexView();\n        }\n\n        private void rAMToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            ChangeScope(ScopeType.RAM);\n        }\n\n        private void cPUAddressSpaceToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            ChangeScope(ScopeType.CPU_Address_Space);\n        }\n\n        private void vRAMToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            ChangeScope(ScopeType.VRAM);\n        }\n\n        private void pPUAddressSpaceToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            ChangeScope(ScopeType.PPU_Address_Space);\n        }\n\n        private void oAMToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            ChangeScope(ScopeType.OAM);\n        }\n\n        private void paletteRAMToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            ChangeScope(ScopeType.Palette_RAM);\n        }\n\n        private void copyToClipboardToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            StringBuilder sb = new StringBuilder();\n            for(int i = 0; i < vScrollBar1.Maximum*0x10;i++)\n            {\n                switch (scopeType)\n                {\n                    case ScopeType.RAM:\n                        sb.Append(MainGUI.EMU.RAM[i].ToString(\"X2\") + \" \"); break;\n                    case ScopeType.CPU_Address_Space:\n                        sb.Append(MainGUI.EMU.Observe((ushort)i).ToString(\"X2\") + \" \"); break;\n                    case ScopeType.VRAM:\n                        sb.Append(MainGUI.EMU.VRAM[i].ToString(\"X2\") + \" \"); break;\n                    case ScopeType.PPU_Address_Space:\n                        sb.Append(MainGUI.EMU.ObservePPU((ushort)i).ToString(\"X2\") + \" \"); break;\n                    case ScopeType.OAM:\n                        sb.Append(MainGUI.EMU.OAM[i].ToString(\"X2\") + \" \"); break;\n                    case ScopeType.Palette_RAM:\n                        sb.Append(MainGUI.EMU.PaletteRAM[i].ToString(\"X2\") + \" \"); break;\n                }\n            }\n            Clipboard.SetText(sb.ToString());\n        }\n    }\n}\n"
  },
  {
    "path": "forms/TriCHexEditor.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <metadata name=\"menuStrip1.TrayLocation\" type=\"System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n    <value>17, 17</value>\n  </metadata>\n  <assembly alias=\"System.Drawing\" name=\"System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\" />\n  <data name=\"$this.Icon\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAA/wAA\n        AP8AAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAA\n        AP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA\n        AAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAA\n        AP8AAAD/AAAA/wAAAP8AAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAAAAAA\n        AAD///////////////////////////////8AAAAAAAAAAAAAAP8AAAD/AAAAAAAAAAD/////////////\n        //////////////////8AAAAAAAAAAAAAAP8AAAD/////////////////////////////////AAAAAAAA\n        AAAAAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//\n        /////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAA\n        AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////\n        ////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA////////\n        //8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAA\n        AP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAA\n        AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//\n        ////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAA\n        AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAA\n        AAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA////////\n        //8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA\n        AAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA\n        AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAA\n        AP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAA\n        AAAAAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//\n        ////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAA\n        AP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA\n        AAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/////////\n        //8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD//////////////////////wAA\n        AP8AAAD/AAAAAAAAAAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAA\n        AAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAAAAD/////////////\n        ////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/////////\n        //8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD///////////8AAAAAAAAAAAAA\n        AAAAAAAA//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////\n        //8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////////8AAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////////\n        /////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////////////////////////wAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAA///////////////////////////////////////////A8D8DwPA/AwPA\n        zAwDwMwMww8A8MMPAPDDDwDwww8A8MMPAPDDDwDwww8A8MMPAPADMDMDAzAzA8/A/A/PwPwP////////\n        //////////////////////////////////8=\n</value>\n  </data>\n</root>"
  },
  {
    "path": "forms/TriCNESGUI.Designer.cs",
    "content": "﻿using System.Threading;\nusing System.Windows.Forms;\n\nnamespace TriCNES\n{\n    partial class TriCNESGUI\n    {\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private System.ComponentModel.IContainer components = null;\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        /// <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing && (components != null))\n            {\n                components.Dispose();\n            }\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TriCNESGUI));\n            this.menuStrip1 = new System.Windows.Forms.MenuStrip();\n            this.consoleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.loadROMToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.resetToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.powerCycleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.screenshotToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.saveStateToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.loadStateToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.tASToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.loadTASToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.load3ctToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.pPUClockToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.phase0ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.phase1ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.phase2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.phase3ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.decodeNTSCSignalsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.trueToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.showRawSignalsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.falseToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.viewBoarderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.toolstrip_ViewBorders_True = new System.Windows.Forms.ToolStripMenuItem();\n            this.toolstrip_ViewBorders_False = new System.Windows.Forms.ToolStripMenuItem();\n            this.viewScaleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.xToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.xToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();\n            this.xToolStripMenuItem2 = new System.Windows.Forms.ToolStripMenuItem();\n            this.xToolStripMenuItem3 = new System.Windows.Forms.ToolStripMenuItem();\n            this.xToolStripMenuItem4 = new System.Windows.Forms.ToolStripMenuItem();\n            this.xToolStripMenuItem5 = new System.Windows.Forms.ToolStripMenuItem();\n            this.xToolStripMenuItem6 = new System.Windows.Forms.ToolStripMenuItem();\n            this.xToolStripMenuItem7 = new System.Windows.Forms.ToolStripMenuItem();\n            this.toolsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.traceLoggerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.nametableViewerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.tASTimelineToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.pb_Screen = new TriCNES.PictureBoxWithInterpolationMode();\n            this.hexEditorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.menuStrip1.SuspendLayout();\n            ((System.ComponentModel.ISupportInitialize)(this.pb_Screen)).BeginInit();\n            this.SuspendLayout();\n            // \n            // menuStrip1\n            // \n            this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {\n            this.consoleToolStripMenuItem,\n            this.tASToolStripMenuItem,\n            this.settingsToolStripMenuItem,\n            this.toolsToolStripMenuItem});\n            this.menuStrip1.Location = new System.Drawing.Point(0, 0);\n            this.menuStrip1.Name = \"menuStrip1\";\n            this.menuStrip1.Size = new System.Drawing.Size(256, 24);\n            this.menuStrip1.TabIndex = 0;\n            this.menuStrip1.Text = \"menuStrip1\";\n            // \n            // consoleToolStripMenuItem\n            // \n            this.consoleToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {\n            this.loadROMToolStripMenuItem,\n            this.resetToolStripMenuItem,\n            this.powerCycleToolStripMenuItem,\n            this.screenshotToolStripMenuItem,\n            this.saveStateToolStripMenuItem,\n            this.loadStateToolStripMenuItem});\n            this.consoleToolStripMenuItem.Name = \"consoleToolStripMenuItem\";\n            this.consoleToolStripMenuItem.Size = new System.Drawing.Size(62, 20);\n            this.consoleToolStripMenuItem.Text = \"Console\";\n            // \n            // loadROMToolStripMenuItem\n            // \n            this.loadROMToolStripMenuItem.Name = \"loadROMToolStripMenuItem\";\n            this.loadROMToolStripMenuItem.Size = new System.Drawing.Size(139, 22);\n            this.loadROMToolStripMenuItem.Text = \"Load ROM\";\n            this.loadROMToolStripMenuItem.Click += new System.EventHandler(this.loadROMToolStripMenuItem_Click);\n            // \n            // resetToolStripMenuItem\n            // \n            this.resetToolStripMenuItem.Name = \"resetToolStripMenuItem\";\n            this.resetToolStripMenuItem.Size = new System.Drawing.Size(139, 22);\n            this.resetToolStripMenuItem.Text = \"Reset\";\n            this.resetToolStripMenuItem.Click += new System.EventHandler(this.resetToolStripMenuItem_Click);\n            // \n            // powerCycleToolStripMenuItem\n            // \n            this.powerCycleToolStripMenuItem.Name = \"powerCycleToolStripMenuItem\";\n            this.powerCycleToolStripMenuItem.Size = new System.Drawing.Size(139, 22);\n            this.powerCycleToolStripMenuItem.Text = \"Power Cycle\";\n            this.powerCycleToolStripMenuItem.Click += new System.EventHandler(this.powerCycleToolStripMenuItem_Click);\n            // \n            // screenshotToolStripMenuItem\n            // \n            this.screenshotToolStripMenuItem.Name = \"screenshotToolStripMenuItem\";\n            this.screenshotToolStripMenuItem.Size = new System.Drawing.Size(139, 22);\n            this.screenshotToolStripMenuItem.Text = \"Screenshot\";\n            this.screenshotToolStripMenuItem.Click += new System.EventHandler(this.screenshotToolStripMenuItem_Click);\n            // \n            // saveStateToolStripMenuItem\n            // \n            this.saveStateToolStripMenuItem.Name = \"saveStateToolStripMenuItem\";\n            this.saveStateToolStripMenuItem.Size = new System.Drawing.Size(139, 22);\n            this.saveStateToolStripMenuItem.Text = \"Save State\";\n            this.saveStateToolStripMenuItem.Click += new System.EventHandler(this.saveStateToolStripMenuItem_Click);\n            // \n            // loadStateToolStripMenuItem\n            // \n            this.loadStateToolStripMenuItem.Name = \"loadStateToolStripMenuItem\";\n            this.loadStateToolStripMenuItem.Size = new System.Drawing.Size(139, 22);\n            this.loadStateToolStripMenuItem.Text = \"Load State\";\n            this.loadStateToolStripMenuItem.Click += new System.EventHandler(this.loadStateToolStripMenuItem_Click);\n            // \n            // tASToolStripMenuItem\n            // \n            this.tASToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {\n            this.loadTASToolStripMenuItem,\n            this.load3ctToolStripMenuItem});\n            this.tASToolStripMenuItem.Name = \"tASToolStripMenuItem\";\n            this.tASToolStripMenuItem.Size = new System.Drawing.Size(38, 20);\n            this.tASToolStripMenuItem.Text = \"TAS\";\n            // \n            // loadTASToolStripMenuItem\n            // \n            this.loadTASToolStripMenuItem.Name = \"loadTASToolStripMenuItem\";\n            this.loadTASToolStripMenuItem.Size = new System.Drawing.Size(144, 22);\n            this.loadTASToolStripMenuItem.Text = \"Load TAS\";\n            this.loadTASToolStripMenuItem.Click += new System.EventHandler(this.loadTASToolStripMenuItem_Click);\n            // \n            // load3ctToolStripMenuItem\n            // \n            this.load3ctToolStripMenuItem.Name = \"load3ctToolStripMenuItem\";\n            this.load3ctToolStripMenuItem.Size = new System.Drawing.Size(144, 22);\n            this.load3ctToolStripMenuItem.Text = \"Load .3ct TAS\";\n            this.load3ctToolStripMenuItem.Click += new System.EventHandler(this.load3ctToolStripMenuItem_Click);\n            // \n            // settingsToolStripMenuItem\n            // \n            this.settingsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {\n            this.pPUClockToolStripMenuItem,\n            this.decodeNTSCSignalsToolStripMenuItem,\n            this.viewBoarderToolStripMenuItem,\n            this.viewScaleToolStripMenuItem});\n            this.settingsToolStripMenuItem.Name = \"settingsToolStripMenuItem\";\n            this.settingsToolStripMenuItem.Size = new System.Drawing.Size(61, 20);\n            this.settingsToolStripMenuItem.Text = \"Settings\";\n            // \n            // pPUClockToolStripMenuItem\n            // \n            this.pPUClockToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {\n            this.phase0ToolStripMenuItem,\n            this.phase1ToolStripMenuItem,\n            this.phase2ToolStripMenuItem,\n            this.phase3ToolStripMenuItem});\n            this.pPUClockToolStripMenuItem.Name = \"pPUClockToolStripMenuItem\";\n            this.pPUClockToolStripMenuItem.Size = new System.Drawing.Size(186, 22);\n            this.pPUClockToolStripMenuItem.Text = \"PPU Clock\";\n            // \n            // phase0ToolStripMenuItem\n            // \n            this.phase0ToolStripMenuItem.Checked = true;\n            this.phase0ToolStripMenuItem.CheckOnClick = true;\n            this.phase0ToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;\n            this.phase0ToolStripMenuItem.Name = \"phase0ToolStripMenuItem\";\n            this.phase0ToolStripMenuItem.Size = new System.Drawing.Size(114, 22);\n            this.phase0ToolStripMenuItem.Text = \"Phase 0\";\n            this.phase0ToolStripMenuItem.Click += new System.EventHandler(this.phase0ToolStripMenuItem_Click);\n            // \n            // phase1ToolStripMenuItem\n            // \n            this.phase1ToolStripMenuItem.CheckOnClick = true;\n            this.phase1ToolStripMenuItem.Name = \"phase1ToolStripMenuItem\";\n            this.phase1ToolStripMenuItem.Size = new System.Drawing.Size(114, 22);\n            this.phase1ToolStripMenuItem.Text = \"Phase 1\";\n            this.phase1ToolStripMenuItem.Click += new System.EventHandler(this.phase1ToolStripMenuItem_Click);\n            // \n            // phase2ToolStripMenuItem\n            // \n            this.phase2ToolStripMenuItem.CheckOnClick = true;\n            this.phase2ToolStripMenuItem.Name = \"phase2ToolStripMenuItem\";\n            this.phase2ToolStripMenuItem.Size = new System.Drawing.Size(114, 22);\n            this.phase2ToolStripMenuItem.Text = \"Phase 2\";\n            this.phase2ToolStripMenuItem.Click += new System.EventHandler(this.phase2ToolStripMenuItem_Click);\n            // \n            // phase3ToolStripMenuItem\n            // \n            this.phase3ToolStripMenuItem.CheckOnClick = true;\n            this.phase3ToolStripMenuItem.Name = \"phase3ToolStripMenuItem\";\n            this.phase3ToolStripMenuItem.Size = new System.Drawing.Size(114, 22);\n            this.phase3ToolStripMenuItem.Text = \"Phase 3\";\n            this.phase3ToolStripMenuItem.Click += new System.EventHandler(this.phase3ToolStripMenuItem_Click);\n            // \n            // decodeNTSCSignalsToolStripMenuItem\n            // \n            this.decodeNTSCSignalsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {\n            this.trueToolStripMenuItem,\n            this.showRawSignalsToolStripMenuItem,\n            this.falseToolStripMenuItem});\n            this.decodeNTSCSignalsToolStripMenuItem.Name = \"decodeNTSCSignalsToolStripMenuItem\";\n            this.decodeNTSCSignalsToolStripMenuItem.Size = new System.Drawing.Size(186, 22);\n            this.decodeNTSCSignalsToolStripMenuItem.Text = \"Decode NTSC Signals\";\n            // \n            // trueToolStripMenuItem\n            // \n            this.trueToolStripMenuItem.Name = \"trueToolStripMenuItem\";\n            this.trueToolStripMenuItem.Size = new System.Drawing.Size(164, 22);\n            this.trueToolStripMenuItem.Text = \"True\";\n            this.trueToolStripMenuItem.Click += new System.EventHandler(this.trueToolStripMenuItem_Click);\n            // \n            // showRawSignalsToolStripMenuItem\n            // \n            this.showRawSignalsToolStripMenuItem.Name = \"showRawSignalsToolStripMenuItem\";\n            this.showRawSignalsToolStripMenuItem.Size = new System.Drawing.Size(164, 22);\n            this.showRawSignalsToolStripMenuItem.Text = \"Show raw signals\";\n            this.showRawSignalsToolStripMenuItem.Click += new System.EventHandler(this.showRawSignalsToolStripMenuItem_Click);\n            // \n            // falseToolStripMenuItem\n            // \n            this.falseToolStripMenuItem.Checked = true;\n            this.falseToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;\n            this.falseToolStripMenuItem.Name = \"falseToolStripMenuItem\";\n            this.falseToolStripMenuItem.Size = new System.Drawing.Size(164, 22);\n            this.falseToolStripMenuItem.Text = \"False\";\n            this.falseToolStripMenuItem.Click += new System.EventHandler(this.falseToolStripMenuItem_Click);\n            // \n            // viewBoarderToolStripMenuItem\n            // \n            this.viewBoarderToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {\n            this.toolstrip_ViewBorders_True,\n            this.toolstrip_ViewBorders_False});\n            this.viewBoarderToolStripMenuItem.Name = \"viewBoarderToolStripMenuItem\";\n            this.viewBoarderToolStripMenuItem.Size = new System.Drawing.Size(186, 22);\n            this.viewBoarderToolStripMenuItem.Text = \"View Border\";\n            // \n            // toolstrip_ViewBorders_True\n            // \n            this.toolstrip_ViewBorders_True.Name = \"toolstrip_ViewBorders_True\";\n            this.toolstrip_ViewBorders_True.Size = new System.Drawing.Size(100, 22);\n            this.toolstrip_ViewBorders_True.Text = \"True\";\n            this.toolstrip_ViewBorders_True.Click += new System.EventHandler(this.trueToolStripMenuItem1_Click);\n            // \n            // toolstrip_ViewBorders_False\n            // \n            this.toolstrip_ViewBorders_False.Checked = true;\n            this.toolstrip_ViewBorders_False.CheckState = System.Windows.Forms.CheckState.Checked;\n            this.toolstrip_ViewBorders_False.Name = \"toolstrip_ViewBorders_False\";\n            this.toolstrip_ViewBorders_False.Size = new System.Drawing.Size(100, 22);\n            this.toolstrip_ViewBorders_False.Text = \"False\";\n            this.toolstrip_ViewBorders_False.Click += new System.EventHandler(this.falseToolStripMenuItem1_Click);\n            // \n            // viewScaleToolStripMenuItem\n            // \n            this.viewScaleToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {\n            this.xToolStripMenuItem,\n            this.xToolStripMenuItem1,\n            this.xToolStripMenuItem2,\n            this.xToolStripMenuItem3,\n            this.xToolStripMenuItem4,\n            this.xToolStripMenuItem5,\n            this.xToolStripMenuItem6,\n            this.xToolStripMenuItem7});\n            this.viewScaleToolStripMenuItem.Name = \"viewScaleToolStripMenuItem\";\n            this.viewScaleToolStripMenuItem.Size = new System.Drawing.Size(186, 22);\n            this.viewScaleToolStripMenuItem.Text = \"View Scale\";\n            // \n            // xToolStripMenuItem\n            // \n            this.xToolStripMenuItem.Name = \"xToolStripMenuItem\";\n            this.xToolStripMenuItem.Size = new System.Drawing.Size(86, 22);\n            this.xToolStripMenuItem.Text = \"1x\";\n            this.xToolStripMenuItem.Click += new System.EventHandler(this.xToolStripMenuItem_Click);\n            // \n            // xToolStripMenuItem1\n            // \n            this.xToolStripMenuItem1.Name = \"xToolStripMenuItem1\";\n            this.xToolStripMenuItem1.Size = new System.Drawing.Size(86, 22);\n            this.xToolStripMenuItem1.Text = \"2x\";\n            this.xToolStripMenuItem1.Click += new System.EventHandler(this.xToolStripMenuItem1_Click);\n            // \n            // xToolStripMenuItem2\n            // \n            this.xToolStripMenuItem2.Name = \"xToolStripMenuItem2\";\n            this.xToolStripMenuItem2.Size = new System.Drawing.Size(86, 22);\n            this.xToolStripMenuItem2.Text = \"3x\";\n            this.xToolStripMenuItem2.Click += new System.EventHandler(this.xToolStripMenuItem2_Click);\n            // \n            // xToolStripMenuItem3\n            // \n            this.xToolStripMenuItem3.Name = \"xToolStripMenuItem3\";\n            this.xToolStripMenuItem3.Size = new System.Drawing.Size(86, 22);\n            this.xToolStripMenuItem3.Text = \"4x\";\n            this.xToolStripMenuItem3.Click += new System.EventHandler(this.xToolStripMenuItem3_Click);\n            // \n            // xToolStripMenuItem4\n            // \n            this.xToolStripMenuItem4.Name = \"xToolStripMenuItem4\";\n            this.xToolStripMenuItem4.Size = new System.Drawing.Size(86, 22);\n            this.xToolStripMenuItem4.Text = \"5x\";\n            this.xToolStripMenuItem4.Click += new System.EventHandler(this.xToolStripMenuItem4_Click);\n            // \n            // xToolStripMenuItem5\n            // \n            this.xToolStripMenuItem5.Name = \"xToolStripMenuItem5\";\n            this.xToolStripMenuItem5.Size = new System.Drawing.Size(86, 22);\n            this.xToolStripMenuItem5.Text = \"6x\";\n            this.xToolStripMenuItem5.Click += new System.EventHandler(this.xToolStripMenuItem5_Click);\n            // \n            // xToolStripMenuItem6\n            // \n            this.xToolStripMenuItem6.Name = \"xToolStripMenuItem6\";\n            this.xToolStripMenuItem6.Size = new System.Drawing.Size(86, 22);\n            this.xToolStripMenuItem6.Text = \"7x\";\n            this.xToolStripMenuItem6.Click += new System.EventHandler(this.xToolStripMenuItem6_Click);\n            // \n            // xToolStripMenuItem7\n            // \n            this.xToolStripMenuItem7.Name = \"xToolStripMenuItem7\";\n            this.xToolStripMenuItem7.Size = new System.Drawing.Size(86, 22);\n            this.xToolStripMenuItem7.Text = \"8x\";\n            this.xToolStripMenuItem7.Click += new System.EventHandler(this.xToolStripMenuItem7_Click);\n            // \n            // toolsToolStripMenuItem\n            // \n            this.toolsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {\n            this.traceLoggerToolStripMenuItem,\n            this.nametableViewerToolStripMenuItem,\n            this.tASTimelineToolStripMenuItem,\n            this.hexEditorToolStripMenuItem});\n            this.toolsToolStripMenuItem.Name = \"toolsToolStripMenuItem\";\n            this.toolsToolStripMenuItem.Size = new System.Drawing.Size(46, 20);\n            this.toolsToolStripMenuItem.Text = \"Tools\";\n            // \n            // traceLoggerToolStripMenuItem\n            // \n            this.traceLoggerToolStripMenuItem.Name = \"traceLoggerToolStripMenuItem\";\n            this.traceLoggerToolStripMenuItem.Size = new System.Drawing.Size(180, 22);\n            this.traceLoggerToolStripMenuItem.Text = \"TraceLogger\";\n            this.traceLoggerToolStripMenuItem.Click += new System.EventHandler(this.traceLoggerToolStripMenuItem_Click);\n            // \n            // nametableViewerToolStripMenuItem\n            // \n            this.nametableViewerToolStripMenuItem.Name = \"nametableViewerToolStripMenuItem\";\n            this.nametableViewerToolStripMenuItem.Size = new System.Drawing.Size(180, 22);\n            this.nametableViewerToolStripMenuItem.Text = \"Nametable Viewer\";\n            this.nametableViewerToolStripMenuItem.Click += new System.EventHandler(this.nametableViewerToolStripMenuItem_Click);\n            // \n            // tASTimelineToolStripMenuItem\n            // \n            this.tASTimelineToolStripMenuItem.Name = \"tASTimelineToolStripMenuItem\";\n            this.tASTimelineToolStripMenuItem.Size = new System.Drawing.Size(180, 22);\n            this.tASTimelineToolStripMenuItem.Text = \"TAS Timeline\";\n            this.tASTimelineToolStripMenuItem.Click += new System.EventHandler(this.tASTimelineToolStripMenuItem_Click);\n            // \n            // pb_Screen\n            // \n            this.pb_Screen.AllowDrop = true;\n            this.pb_Screen.BackColor = System.Drawing.Color.Black;\n            this.pb_Screen.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;\n            this.pb_Screen.Location = new System.Drawing.Point(0, 27);\n            this.pb_Screen.Name = \"pb_Screen\";\n            this.pb_Screen.Size = new System.Drawing.Size(256, 240);\n            this.pb_Screen.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;\n            this.pb_Screen.TabIndex = 1;\n            this.pb_Screen.TabStop = false;\n            // \n            // hexEditorToolStripMenuItem\n            // \n            this.hexEditorToolStripMenuItem.Name = \"hexEditorToolStripMenuItem\";\n            this.hexEditorToolStripMenuItem.Size = new System.Drawing.Size(180, 22);\n            this.hexEditorToolStripMenuItem.Text = \"Hex Editor\";\n            this.hexEditorToolStripMenuItem.Click += new System.EventHandler(this.hexEditorToolStripMenuItem_Click);\n            // \n            // TriCNESGUI\n            // \n            this.AllowDrop = true;\n            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);\n            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;\n            this.AutoValidate = System.Windows.Forms.AutoValidate.EnableAllowFocusChange;\n            this.ClientSize = new System.Drawing.Size(256, 267);\n            this.Controls.Add(this.pb_Screen);\n            this.Controls.Add(this.menuStrip1);\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;\n            this.Icon = ((System.Drawing.Icon)(resources.GetObject(\"$this.Icon\")));\n            this.KeyPreview = true;\n            this.MainMenuStrip = this.menuStrip1;\n            this.MaximizeBox = false;\n            this.MaximumSize = new System.Drawing.Size(272, 306);\n            this.MinimizeBox = false;\n            this.MinimumSize = new System.Drawing.Size(272, 306);\n            this.Name = \"TriCNESGUI\";\n            this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;\n            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;\n            this.Text = \"TriCNES GUI\";\n            this.menuStrip1.ResumeLayout(false);\n            this.menuStrip1.PerformLayout();\n            ((System.ComponentModel.ISupportInitialize)(this.pb_Screen)).EndInit();\n            this.ResumeLayout(false);\n            this.PerformLayout();\n\n        }\n\n        #endregion\n\n        private System.Windows.Forms.MenuStrip menuStrip1;\n        private System.Windows.Forms.ToolStripMenuItem consoleToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem tASToolStripMenuItem;\n        private PictureBoxWithInterpolationMode pb_Screen;\n        private System.Windows.Forms.ToolStripMenuItem loadROMToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem loadTASToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem load3ctToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem resetToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem powerCycleToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem screenshotToolStripMenuItem;\n        private ToolStripMenuItem settingsToolStripMenuItem;\n        private ToolStripMenuItem pPUClockToolStripMenuItem;\n        private ToolStripMenuItem phase0ToolStripMenuItem;\n        private ToolStripMenuItem phase1ToolStripMenuItem;\n        private ToolStripMenuItem phase2ToolStripMenuItem;\n        private ToolStripMenuItem phase3ToolStripMenuItem;\n        private ToolStripMenuItem decodeNTSCSignalsToolStripMenuItem;\n        private ToolStripMenuItem trueToolStripMenuItem;\n        private ToolStripMenuItem falseToolStripMenuItem;\n        private ToolStripMenuItem viewScaleToolStripMenuItem;\n        private ToolStripMenuItem xToolStripMenuItem;\n        private ToolStripMenuItem xToolStripMenuItem1;\n        private ToolStripMenuItem xToolStripMenuItem2;\n        private ToolStripMenuItem xToolStripMenuItem3;\n        private ToolStripMenuItem xToolStripMenuItem4;\n        private ToolStripMenuItem xToolStripMenuItem5;\n        private ToolStripMenuItem xToolStripMenuItem6;\n        private ToolStripMenuItem xToolStripMenuItem7;\n        private ToolStripMenuItem toolsToolStripMenuItem;\n        private ToolStripMenuItem traceLoggerToolStripMenuItem;\n        private ToolStripMenuItem viewBoarderToolStripMenuItem;\n        private ToolStripMenuItem toolstrip_ViewBorders_True;\n        private ToolStripMenuItem toolstrip_ViewBorders_False;\n        private ToolStripMenuItem nametableViewerToolStripMenuItem;\n        private ToolStripMenuItem showRawSignalsToolStripMenuItem;\n        private ToolStripMenuItem saveStateToolStripMenuItem;\n        private ToolStripMenuItem loadStateToolStripMenuItem;\n        private ToolStripMenuItem tASTimelineToolStripMenuItem;\n        private ToolStripMenuItem hexEditorToolStripMenuItem;\n    }\n}\n\n"
  },
  {
    "path": "forms/TriCNESGUI.cs",
    "content": "﻿using SDL2;\nusing System;\nusing System.Collections.Generic;\nusing System.Data;\nusing System.Drawing;\nusing System.Drawing.Drawing2D;\nusing System.IO;\nusing System.IO.Compression;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Windows.Forms;\nusing System.Windows.Input;\n\nnamespace TriCNES\n{\n    public partial class TriCNESGUI : Form\n    {\n        // This is the the main window for a user to interact with this emulator.\n        // The logic for the emulator is contained entirely in a single C# file, for easy use importing it into other projects.\n        // this form here is intended to be used an an example.\n        // The intended use for this emulator is to run your own code specifically to collect data, but do with it as you please.\n        // Cheers! ~ Chris \"100th_Coin\" Siebert\n        public TriCNESGUI()\n        {\n            InitializeComponent();\n            pb_Screen.DragEnter += new DragEventHandler(pb_Screen_DragEnter);\n            pb_Screen.DragDrop += new DragEventHandler(pb_Screen_DragDrop);\n            FormClosing += new FormClosingEventHandler(TriCNESGUI_Closing);\n            SDL.SDL_Init(SDL.SDL_INIT_GAMECONTROLLER);\n            SDL.SDL_GameControllerEventState(SDL.SDL_ENABLE);\n            SDL.SDL_GameControllerUpdate();\n            int c = SDL.SDL_NumJoysticks();\n            if (c != 0)\n            {\n                joystickptr = SDL.SDL_JoystickOpen(0);\n                gameControllerPrt = SDL.SDL_GameControllerOpen(0);\n            }\n        }\n        IntPtr joystickptr;\n        IntPtr gameControllerPrt;\n\n        bool settings_ntsc;\n        bool settings_ntscRaw;\n        bool settings_border;\n        byte settings_alignment;\n\n        public Emulator EMU;\n        public Thread EmuClock;\n        string filePath;\n        bool FDS;\n        TASProperties TASPropertiesForm;\n        TASProperties3ct TASPropertiesForm3ct;\n        public TriCTraceLogger? TraceLogger;\n        public TriCNTViewer? NametableViewer;\n        public TriCTASTimeline? TasTimeline;\n        public TriCHexEditor? HexExditor;\n\n        void RunUpkeep()\n        {\n            if (PendingScreenshot)\n            {\n                PendingScreenshot = false;\n                if (EMU.PPU_DecodeSignal)\n                {\n                    if (EMU.PPU_ShowScreenBorders)\n                    {\n                        Clipboard.SetImage(EMU.BorderedNTSCScreen.Bitmap);\n                    }\n                    else\n                    {\n                        Clipboard.SetImage(EMU.NTSCScreen.Bitmap);\n                    }\n                }\n                else\n                {\n                    if (EMU.PPU_ShowScreenBorders)\n                    {\n                        Clipboard.SetImage(EMU.BorderedScreen.Bitmap);\n                    }\n                    else\n                    {\n                        Clipboard.SetImage(EMU.Screen.Bitmap);\n                    }\n                }\n            }\n            if (Pending_ShowScreenBorders)\n            {\n                Pending_ShowScreenBorders = false;\n                EMU.PPU_ShowScreenBorders = true;\n                BeginInvoke(new MethodInvoker(delegate () { ResizeWindow(ScreenMult); }));\n            }\n            if (Pending_HideScreenBorders)\n            {\n                Pending_HideScreenBorders = false;\n                EMU.PPU_ShowScreenBorders = false;\n                BeginInvoke(new MethodInvoker(delegate () { ResizeWindow(ScreenMult); }));\n            }\n            if (PendingSaveState)\n            {\n                PendingSaveState = false;\n                Savestate = EMU.SaveState();\n            }\n            if (PendingLoadState && Savestate != null && Savestate.Count > 0)\n            {\n                PendingLoadState = false;\n                EMU.LoadState(Savestate);\n            }\n            if (TraceLogger != null)\n            {\n                EMU.Logging = TraceLogger.Logging;\n                if (EMU.DebugLog == null)\n                {\n                    EMU.DebugLog = new StringBuilder();\n                }\n                EMU.DebugRange_Low = TraceLogger.RangeLow;\n                EMU.DebugRange_High = TraceLogger.RangeHigh;\n                EMU.OnlyDebugInRange = TraceLogger.OnlyDebugInRange();\n                EMU.LoggingPPU = TraceLogger.LogPPUCycles();\n            }\n            else if(EMU.Logging)\n            {\n                EMU.Logging = false;\n                EMU.DebugLog = new StringBuilder();\n            }\n            if(HexExditor != null)\n            {\n                HexExditor.Update();\n            }\n        }\n\n        void RunPostFramePhase()\n        {\n            if (TraceLogger != null)\n            {\n                if (TraceLogger.Logging)\n                {\n                    TraceLogger.Update();\n                    if (TraceLogger.ClearEveryFrame())\n                    {\n                        EMU.DebugLog = new StringBuilder();\n                    }\n                }\n            }\n            if (NametableViewer != null && !NametableViewer.IsDisposed)\n            {\n                RenderNametable();\n                NametableViewer.Update(NametableBitmap.Bitmap);\n            }\n            if (pb_Screen.InvokeRequired)\n            {\n                pb_Screen.BeginInvoke(new MethodInvoker(\n                delegate ()\n                {\n                    if (EMU.PPU_DecodeSignal)\n                    {\n                        if (EMU.PPU_ShowScreenBorders)\n                        {\n                            pb_Screen.Image = EMU.BorderedNTSCScreen.Bitmap;\n                        }\n                        else\n                        {\n                            pb_Screen.Image = EMU.NTSCScreen.Bitmap;\n                        }\n                    }\n                    else\n                    {\n                        if (EMU.PPU_ShowScreenBorders)\n                        {\n                            pb_Screen.Image = EMU.BorderedScreen.Bitmap;\n                        }\n                        else\n                        {\n                            pb_Screen.Image = EMU.Screen.Bitmap;\n                        }\n                    }\n                    pb_Screen.Update();\n                }));\n            }\n            else\n            {\n                if (EMU.PPU_DecodeSignal)\n                {\n                    if (EMU.PPU_ShowScreenBorders)\n                    {\n                        pb_Screen.Image = EMU.BorderedNTSCScreen.Bitmap;\n                    }\n                    else\n                    {\n                        pb_Screen.Image = EMU.NTSCScreen.Bitmap;\n                    }\n                }\n                else\n                {\n                    if (EMU.PPU_ShowScreenBorders)\n                    {\n                        pb_Screen.Image = EMU.BorderedScreen.Bitmap;\n                    }\n                    else\n                    {\n                        pb_Screen.Image = EMU.Screen.Bitmap;\n                    }\n                }\n                pb_Screen.Update();\n            }\n            \n        }\n\n        bool[] ControllerInputs()\n        {\n            bool[] joystickButtons = new bool[8];\n            \n            int c = SDL.SDL_NumJoysticks();\n            if (c != 0)\n            {\n                SDL.SDL_GameControllerUpdate();\n\n                joystickButtons[0] = SDL.SDL_GameControllerGetButton(gameControllerPrt, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_RIGHT) != 0;\n                joystickButtons[1] = SDL.SDL_GameControllerGetButton(gameControllerPrt, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_LEFT) != 0;\n                joystickButtons[2] = SDL.SDL_GameControllerGetButton(gameControllerPrt, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_DOWN) != 0;\n                joystickButtons[3] = SDL.SDL_GameControllerGetButton(gameControllerPrt, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_UP) != 0;\n                joystickButtons[4] = SDL.SDL_GameControllerGetButton(gameControllerPrt, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_START) != 0;\n                joystickButtons[5] = SDL.SDL_GameControllerGetButton(gameControllerPrt, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_BACK) != 0;\n                joystickButtons[6] = SDL.SDL_GameControllerGetButton(gameControllerPrt, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_X) != 0;\n                joystickButtons[7] = SDL.SDL_GameControllerGetButton(gameControllerPrt, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_A) != 0;\n            }\n            else\n            {\n                for (int i = 0; i < 8; i++)\n                {\n                    joystickButtons[i] = false;\n                }\n            }\n            return joystickButtons;\n        }\n\n        byte RealtimeInputs()\n        {\n            bool[] joystickButtons = ControllerInputs();\n\n            byte controller1 = 0;\n            if (joystickButtons[7] || Keyboard.IsKeyDown(Key.X)) { controller1 |= 0x80; }\n            if (joystickButtons[6] || Keyboard.IsKeyDown(Key.Z)) { controller1 |= 0x40; }\n            if (joystickButtons[5] || Keyboard.IsKeyDown(Key.RightShift)) { controller1 |= 0x20; }\n            if (joystickButtons[4] || Keyboard.IsKeyDown(Key.Enter)) { controller1 |= 0x10; }\n            if (joystickButtons[3] || Keyboard.IsKeyDown(Key.Up)) { controller1 |= 0x08; }\n            if (joystickButtons[2] || Keyboard.IsKeyDown(Key.Down)) { controller1 |= 0x04; }\n            if (joystickButtons[1] || Keyboard.IsKeyDown(Key.Left)) { controller1 |= 0x02; }\n            if (joystickButtons[0] || Keyboard.IsKeyDown(Key.Right)) { controller1 |= 0x01; }\n            return controller1;\n        }\n\n        CancellationTokenSource cancel;\n        void ClockEmulator(CancellationToken ct)\n        {\n            int frameCount = 0;\n            \n            while (!ct.IsCancellationRequested)\n            {\n                if (Form.ActiveForm != null)\n                {\n                    if (Keyboard.IsKeyDown(Key.Q)) { PendingSaveState = true; }\n                    if (Keyboard.IsKeyDown(Key.W)) { PendingLoadState = true; }\n                                        \n                    EMU.ControllerPort1 = RealtimeInputs();\n                }\n                RunUpkeep();\n                EMU._CoreFrameAdvance();\n                RunPostFramePhase();\n                frameCount++;\n            }            \n        }\n\n        DirectBitmap NametableBitmap;\n        public Bitmap RenderNametable()\n        {\n\n\n            if (NametableBitmap != null)\n            {\n                NametableBitmap.Dispose();\n            }\n            NametableBitmap = new DirectBitmap(512, 480);\n            if (EMU.Cart == null)\n            {\n                return NametableBitmap.Bitmap;\n            }\n\n            int tx = 0;\n            int ty = 0;\n            int x = 0;\n            int y = 0;\n            int px = 0;\n            int py = 0;\n\n            int PatternTile;\n            int pal = 0;\n\n            bool ForceBackdropOnIndex0 = NametableViewer.UseBackdrop();\n\n            while (ty < 2)\n            {\n                while (tx < 2)\n                {\n                    while (y < 30)\n                    {\n                        while (x < 32)\n                        {\n                            PatternTile = EMU.ObservePPU((ushort)(0x2000 + 0x400 * tx + 0x800 * ty + x + y * 32));\n                            pal = EMU.ObservePPU((ushort)(0x2000 + 0x400 * (tx + 1) + 0x800 * ty - 0x40 + x / 4 + (y / 4) * 8));\n                            if ((x & 3) >= 2)\n                            {\n                                pal = pal >> 2;\n                            }\n                            if ((y & 3) >= 2)\n                            {\n                                pal = pal >> 4;\n                            }\n                            pal = pal & 3;\n                            while (py < 8)\n                            {\n                                while (px < 8)\n                                {\n\n                                    int k = ((EMU.ObservePPU((ushort)(py + PatternTile * 16 + (!EMU.PPU_PatternSelect_Background ? 0 : 0x1000))) >> (7 - px)) & 1) + 2 * ((EMU.ObservePPU((ushort)(py + 8 + PatternTile * 16 + (!EMU.PPU_PatternSelect_Background ? 0 : 0x1000))) >> (7 - px)) & 1);\n                                    if (k == 0 && ForceBackdropOnIndex0)\n                                    {\n                                        k = EMU.ObservePPU(0x3F00);\n                                    }\n                                    else\n                                    {\n                                        k = EMU.ObservePPU((ushort)(0x3F00 + k + pal * 4));\n                                    }\n                                    int col = unchecked((int)Emulator.NesPalInts[k & 0x3F]);\n                                    NametableBitmap.SetPixel(tx * 0x100 + x * 8 + px, ty * 0xF0 + y * 8 + py, col);\n                                    px++;\n                                }\n                                px = 0;\n                                py++;\n                            }\n                            py = 0;\n                            x++;\n                        }\n\n                        x = 0;\n                        y++;\n                    }\n                    y = 0;\n                    tx++;\n                }\n                tx = 0;\n                ty++;\n            }\n\n            bool DrawScreenBoundary = NametableViewer.DrawBoundary();\n            if (DrawScreenBoundary)\n            {\n                // convert the t register into X,Y coordinates\n                /*\n                The v and t registers are 15 bits:\n                yyy NN YYYYY XXXXX\n                ||| || ||||| +++++-- coarse X scroll\n                ||| || +++++-------- coarse Y scroll\n                ||| ++-------------- nametable select\n                +++----------------- fine Y scroll\n                */\n                int X = ((EMU.PPU_t & 0b11111) << 3) | EMU.PPU_FineXScroll | ((EMU.PPU_t & 0b10000000000) >> 2);\n                int Y = ((EMU.PPU_t & 0b1111100000) >> 2) | ((EMU.PPU_t & 0b111000000000000) >> 12) | ((EMU.PPU_t & 0b100000000000) >> 4);\n                int i = 0;\n                while (i <= 257)\n                {\n                    NametableBitmap.SetPixel((X + 511 + i) & 511, (Y + 479) % 480, Color.White);\n                    NametableBitmap.SetPixel((X + 511 + i) & 511, (Y + 240) % 480, Color.White);\n                    i++;\n                }\n                i = 0;\n                while (i <= 241)\n                {\n                    NametableBitmap.SetPixel((X + 511) & 511, (Y + 479 + i) % 480, Color.White);\n                    NametableBitmap.SetPixel((X + 256) & 511, (Y + 479 + i) % 480, Color.White);\n                    i++;\n                }\n            }\n            if (NametableViewer.OverlayScreen())\n            {\n                int X = ((EMU.PPU_t & 0b11111) << 3) | EMU.PPU_FineXScroll | ((EMU.PPU_t & 0b10000000000) >> 2);\n                int Y = ((EMU.PPU_t & 0b1111100000) >> 2) | ((EMU.PPU_t & 0b111000000000000) >> 12) | ((EMU.PPU_t & 0b100000000000) >> 4);\n                for (int xx = 0; xx < 256; xx++)\n                {\n                    for (int yy = 0; yy < 240; yy++)\n                    {\n                        NametableBitmap.SetPixel((X + xx) & 511, (Y + yy) % 480, EMU.Screen.GetPixel(xx, yy));\n                    }\n                }\n            }\n            return NametableBitmap.Bitmap;\n        }\n\n        string fds_bios; // file path to the FDS bios if one is loaded.\n        public bool LoadROM(string FilePath)\n        {\n            if (FDS)\n            {\n                if (fds_bios == null || fds_bios.Length == 0)\n                {\n                    string InitDirectory = AppDomain.CurrentDomain.BaseDirectory;\n                    if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @\"roms\\\"))\n                    {\n                        InitDirectory += @\"roms\\\";\n                    }\n                    OpenFileDialog ofd = new OpenFileDialog()\n                    {\n                        FileName = \"\",\n                        Title = \"Select FDS BIOS\",\n                        InitialDirectory = InitDirectory\n                    };\n                    if (ofd.ShowDialog() == DialogResult.OK)\n                    {\n                        fds_bios = ofd.FileName;\n                        byte[] FDS_BIOS = File.ReadAllBytes(fds_bios);\n                        if (FDS_BIOS.Length != 0x2000)\n                        {\n                            fds_bios = \"\";\n                            return false;\n                        }\n                    }\n                    else\n                    {\n                        return false;\n                    }\n                }\n\n                Cartridge Cart = new Cartridge(filePath, fds_bios);\n                EMU.Cart = Cart;\n                Cart.Emu = EMU;\n                return true;\n            }\n            else\n            {\n                Cartridge Cart = new Cartridge(filePath);\n                EMU.Cart = Cart;\n                Cart.Emu = EMU;\n                return true;\n            }\n            return false;\n        }\n\n        public void InsertDisk(string filepath)\n        {\n            if(EMU.Cart.FDS != null)\n            {\n                EMU.Cart.FDS.InsertDisk(filepath);\n            }\n        }\n\n        void ClockEmulator3CT(CancellationToken ct)\n        {\n            Cartridge[] CartArray = TASPropertiesForm3ct.CartridgeArray;\n            int[] CyclesToSwapOn = TASPropertiesForm3ct.CyclesToSwapOn.ToArray();\n            int[] CartsToSwapIn = TASPropertiesForm3ct.CartsToSwapIn.ToArray();\n            EMU.Cart = CartArray[0];\n\n            int i = 1; // what cycle is being executed next?\n            int j = 0; // what step of the .3ct TAS is this?\n            while (j < CyclesToSwapOn.Length)\n            {\n                if (i == CyclesToSwapOn[j]) // if there's a cart swap on this cycle\n                {\n                    EMU.Cart = CartArray[CartsToSwapIn[j]]; // swap the cartridge to the next one in the list\n                    j++;\n                }\n                EMU._CoreCycleAdvance();\n                i++;\n            }\n            // once the .3ct TAS is completed, continue running the emulator with whatever cartridge is loaded last.\n            while (!ct.IsCancellationRequested)\n            {\n                RunUpkeep();\n                EMU._CoreFrameAdvance();\n                RunPostFramePhase();\n            }\n            \n        }\n\n        private void loadROMToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            string InitDirectory = AppDomain.CurrentDomain.BaseDirectory;\n            if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @\"roms\\\"))\n            {\n                InitDirectory += @\"roms\\\";\n            }\n            OpenFileDialog ofd = new OpenFileDialog()\n            {\n                FileName = \"\",\n                Filter = \"NES ROM files (*.nes)|*.nes\",\n                Title = \"Select file\",\n                InitialDirectory = InitDirectory\n            };\n\n            if (ofd.ShowDialog() == DialogResult.OK)\n            {\n                if (EmuClock != null)\n                {\n                    cancel.Cancel();\n                    EmuClock.Join();\n                }\n                if (EMU != null)\n                {\n                    EMU.Dispose();\n                    GC.Collect();\n                }\n                filePath = ofd.FileName;\n                FDS = Path.GetExtension(ofd.FileName) == \".fds\";\n                EMU = new Emulator();\n                EMU.PPU_DecodeSignal = settings_ntsc;\n                EMU.PPU_ShowRawNTSCSignal = settings_ntscRaw;\n                EMU.PPU_ShowScreenBorders = settings_border;\n                EMU.PPUClock = settings_alignment;\n                if (!LoadROM(filePath)) { return; }\n                cancel = new CancellationTokenSource();\n                EmuClock = new Thread(() => ClockEmulator(cancel.Token));\n                EmuClock.SetApartmentState(ApartmentState.STA);\n                EmuClock.IsBackground = true;\n                EmuClock.Start();\n                GC.Collect();\n            }\n        }\n\n        private void loadTASToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            string InitDirectory = AppDomain.CurrentDomain.BaseDirectory;\n            if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @\"tas\\\"))\n            {\n                InitDirectory += @\"tas\\\";\n            }\n            OpenFileDialog ofd = new OpenFileDialog()\n            {\n                FileName = \"\",\n                Filter =\n                \"All TAS Files (.3c2, .3c3, .bk2, .tasproj, .fm2, .fm3, .fmv, .r08)|*.3c2;*.3c3;*.bk2;*.tasproj;*.fm2;*.fm3;*.fmv;*.r08\" +\n                \"|TriCNES TAS File (.3c2, .3c3)|*.3c2;*.3c3\" +\n                \"|Bizhawk Movie (.bk2)|*.bk2\" +\n                \"|Bizhawk TAStudio (.tasproj)|*.tasproj\" +\n                \"|FCEUX Movie (.fm2)|*.fm2\" +\n                \"|FCEUX TAS Editor (.fm3)|*.fm3\" +\n                \"|Famtastia Movie (.fmv)|*.fmv\" +\n                \"|Replay Device (.r08)|*.r08\",\n                Title = \"Select file\",\n                InitialDirectory = InitDirectory\n            };\n            if (ofd.ShowDialog() == DialogResult.OK)\n            {\n                if (TASPropertiesForm != null)\n                {\n                    TASPropertiesForm.Close();\n                    TASPropertiesForm.Dispose();\n                }\n                TASPropertiesForm = new TASProperties();\n                TASPropertiesForm.TasFilePath = ofd.FileName;\n                TASPropertiesForm.MainGUI = this;\n                TASPropertiesForm.Init();\n                TASPropertiesForm.Show();\n                TASPropertiesForm.Location = Location;\n            }\n        }\n\n        public void StartTAS()\n        {\n            if (filePath == \"\" || filePath == null)\n            {\n                MessageBox.Show(\"You need to select a ROM before running a TAS.\");\n                return;\n            }\n\n            if (EmuClock != null)\n            {\n                cancel.Cancel();\n                EmuClock.Join();\n            }\n\n            if (EMU != null)\n            {\n                EMU.Dispose();\n                GC.Collect();\n            }\n\n            EMU = new Emulator();\n            EMU.PPU_DecodeSignal = settings_ntsc;\n            EMU.PPU_ShowRawNTSCSignal = settings_ntscRaw;\n            EMU.PPU_ShowScreenBorders = settings_border;\n\n            if (!LoadROM(filePath)) { return; }\n\n            EMU.TAS_ReadingTAS = true;\n            EMU.TAS_InputLog = TASPropertiesForm.TasInputLog;\n            EMU.TAS_ResetLog = TASPropertiesForm.TasResetLog;\n            EMU.ClockFiltering = TASPropertiesForm.SubframeInputs();\n            EMU.PPUClock = TASPropertiesForm.GetPPUClockPhase();\n            EMU.CPUClock = TASPropertiesForm.GetCPUClockPhase();\n            EMU.TAS_InputSequenceIndex = 0;\n            switch (TASPropertiesForm.extension)\n            {\n                case \".bk2\":\n                case \".tasproj\":\n                    {\n                        int i = 0;\n                        while (i < EMU.RAM.Length) //bizhawk RAM pattern\n                        {\n                            if ((i & 7) > 4)\n                            {\n                                EMU.RAM[i] = 0xFF;\n                            }\n                            else\n                            {\n                                EMU.RAM[i] = 0;\n                            }\n                            i++;\n                        }\n                    }\n                    break;\n                case \".fm2\":\n                case \".fm3\":\n                    {\n                        if (TASPropertiesForm.UseFCEUXFrame0Timing())\n                        {\n                            // FCEUX incorrectly starts at the beginning of scanline 240, and cycle 0 is *after* the reset instruction.\n                            // However, I think there's some other incorrect timing going on with FCEUX, and in order to sync TASes, I need to start at scanline 239, dot 312\n                            EMU.PPU_Scanline = 239;\n                            EMU.PPU_Dot = 312;\n                            // but of course, by starting here, the VBlank flag will be incorrectly set early.\n                            EMU.SyncFM2 = true; // so this bool prevents that.\n                            EMU.TAS_InputSequenceIndex--; // since this runs an extra vblank, this needs to be offset by 1\n                        }\n                        else\n                        {\n                            EMU.TAS_InputSequenceIndex++;\n                            EMU.PPU_Dot = 0;\n                        }\n                        // FCEUX also starts with this RAM pattern\n                        int i = 0;\n                        while (i < EMU.RAM.Length) //bizhawk RAM pattern\n                        {\n                            if ((i & 7) > 4)\n                            {\n                                EMU.RAM[i] = 0xFF;\n                            }\n                            else\n                            {\n                                EMU.RAM[i] = 0;\n                            }\n                            i++;\n                        }\n                    }\n                    break;\n                case \".r08\":\n                    {\n                        // This following comment block can be removed if you want to set up RAM for the Bad Apple TAS's .r08 file.\n                        /*\n                        string s = \"0000000000000C000000000000000000E2000000001D1E000000000001000000984820BEFE68A8A5F7A6F8600000000010400000000000000000000000000000A2A58EFF07A216EA8EFD07020000000020200091318A11319131C8C430D0F14C40000000000000000101030000000000000000000000000000000000000000000000000000F000000000020000A0A000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000101000000000000000000000000000100000000000000000000000000000000000035000000008E002001008A4820BEFE68AA0C000000004C4000000001A804D9B4B4070004DAB4B4030004DBB4B4030005DCB4B4030004DDB4B4030004DEB4B4030004DFB4B4030004E0B4B4030004E1B4B4030004E2B4B4030004E3B4B4030004E4B4B4030004E5B4B4030004E6B4C886A080F5D000D00B00003F2FC7F8C8FE0024000F5200FB0400A9018D164085C04A8D1640AD16404A26C090F8A5C060A202206B0195C1CA10F8A000206B0191C2C8C4C190F6206B01F0E5206B0185C3206B0185C26CC200FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB00FB003AFB00FB00FB00FB10D2A27DA07DF50400040004D93525D8F70000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8410000F8410000F8250000F8250000F8410000F8410000F8250000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000F8010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000D900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000787A2021047F1918470000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F722CC891000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001600A5\";\n                        int i = 0;\n                        while (i < 0x800)\n                        {\n                            EMU.RAM[i] = byte.Parse(s.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber);\n                            i++;\n                        }\n                        */\n                        break;\n                    }\n            }\n\n            cancel = new CancellationTokenSource();\n            EmuClock = new Thread(() => ClockEmulator(cancel.Token));\n            EmuClock.SetApartmentState(ApartmentState.STA);\n            EmuClock.IsBackground = true;\n            EmuClock.Start();\n            GC.Collect();\n        }\n\n        public void Start3CTTAS()\n        {\n            if (EmuClock != null)\n            {\n                cancel.Cancel();\n                EmuClock.Join();\n                EMU.Dispose();\n            }\n            if (TASPropertiesForm3ct.FromRESET())\n            {\n                if (EMU == null)\n                {\n                    MessageBox.Show(\"The emulator needs to be powered on before running from RESET.\");\n                    return;\n                }\n                EMU.Reset();\n            }\n            else\n            {\n                if (EMU != null)\n                {\n                    EMU.Dispose();\n                    GC.Collect();\n                }\n                EMU = new Emulator();\n                EMU.PPU_DecodeSignal = settings_ntsc;\n                EMU.PPU_ShowRawNTSCSignal = settings_ntscRaw;\n                EMU.PPU_ShowScreenBorders = settings_border;\n                EMU.PPUClock = settings_alignment;\n            }\n            foreach(Cartridge c in TASPropertiesForm3ct.CartridgeArray)\n            {\n                c.Emu = EMU;\n            }\n            cancel = new CancellationTokenSource();\n            EmuClock = new Thread(() => ClockEmulator3CT(cancel.Token));\n            EmuClock.IsBackground = true;\n            EmuClock.Start();\n        }\n\n        private void load3ctToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            string InitDirectory = AppDomain.CurrentDomain.BaseDirectory;\n            if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @\"tas\\\"))\n            {\n                InitDirectory += @\"tas\\\";\n            }\n            OpenFileDialog ofd = new OpenFileDialog()\n            {\n                FileName = \"\",\n                Filter =\n                \"3CT TAS Files (.3ct)|*.3ct\",\n                Title = \"Select file\",\n                InitialDirectory = InitDirectory\n            };\n            if (ofd.ShowDialog() == DialogResult.OK)\n            {\n                if (TASPropertiesForm3ct != null)\n                {\n                    TASPropertiesForm3ct.Close();\n                    TASPropertiesForm3ct.Dispose();\n                }\n                TASPropertiesForm3ct = new TASProperties3ct();\n                TASPropertiesForm3ct.TasFilePath = ofd.FileName;\n                TASPropertiesForm3ct.MainGUI = this;\n                TASPropertiesForm3ct.Init();\n                TASPropertiesForm3ct.Show();\n                TASPropertiesForm3ct.Location = Location;\n            }\n        }\n\n        private void resetToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            if (EMU != null)\n            {\n                EMU.Reset();\n            }\n        }\n\n        private void powerCycleToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            if (EMU != null)\n            {\n                Emulator Emu2 = new Emulator();\n                Emu2.PPU_DecodeSignal = settings_ntsc;\n                EMU.PPU_ShowRawNTSCSignal = settings_ntscRaw;\n                Emu2.PPU_ShowScreenBorders = settings_border;\n                Emu2.PPUClock = settings_alignment;\n                Emu2.Cart = EMU.Cart;\n                Emu2.Cart.Emu = Emu2;\n                EMU = Emu2;\n            }\n        }\n\n        bool PendingScreenshot;\n        private void screenshotToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            PendingScreenshot = true;\n        }\n\n        private void pb_Screen_DragEnter(object sender, DragEventArgs e)\n        {\n            var filenames = (string[])e.Data.GetData(DataFormats.FileDrop, false);\n            if (Path.GetExtension(filenames[0]) == \".nes\" || Path.GetExtension(filenames[0]) == \".NES\" || Path.GetExtension(filenames[0]) == \".fds\" || Path.GetExtension(filenames[0]) == \".FDS\") e.Effect = DragDropEffects.All;\n            else e.Effect = DragDropEffects.None;\n        }\n\n        private void pb_Screen_DragDrop(object sender, DragEventArgs e)\n        {\n            var filenames = (string[])e.Data.GetData(DataFormats.FileDrop, false);\n            string filename = filenames[0];\n            filePath = filename;\n            bool prev_FDS = FDS;\n            FDS = Path.GetExtension(filePath).ToLower() == \".fds\";\n\n            if (!FDS || !prev_FDS)\n            {\n                if (EmuClock != null)\n                {\n                    cancel.Cancel();\n                    EmuClock.Join();\n                }\n\n                if (EMU != null)\n                {\n                    EMU.Dispose();\n                    GC.Collect();\n                }\n            }\n            if (FDS && prev_FDS)\n            {\n                InsertDisk(filePath);\n            }\n            else\n            {\n                EMU = new Emulator();\n                EMU.PPU_DecodeSignal = settings_ntsc;\n                EMU.PPU_ShowRawNTSCSignal = settings_ntscRaw;\n                EMU.PPU_ShowScreenBorders = settings_border;\n                EMU.PPUClock = settings_alignment;\n\n                if (!LoadROM(filePath)) { return; }\n\n                cancel = new CancellationTokenSource();\n                EmuClock = new Thread(() => ClockEmulator(cancel.Token));\n                EmuClock.SetApartmentState(ApartmentState.STA);\n                EmuClock.IsBackground = true;\n                EmuClock.Start();\n            }\n            GC.Collect();\n\n        }\n        private void TriCNESGUI_Closing(Object sender, FormClosingEventArgs e)\n        {\n            if (EmuClock != null)\n            {\n                cancel.Cancel();\n                EmuClock.Join();\n            }\n            if (TASPropertiesForm != null)\n            {\n                TASPropertiesForm.Dispose();\n            }\n            if (TASPropertiesForm3ct != null)\n            {\n                TASPropertiesForm3ct.Dispose();\n            }\n            if (TraceLogger != null)\n            {\n                TraceLogger.Dispose();\n            }\n            if (NametableViewer != null)\n            {\n                NametableViewer.Dispose();\n            }\n            if(TasTimeline != null)\n            {\n                TasTimeline.Dispose();\n            }\n            if (HexExditor != null)\n            {\n                HexExditor.Dispose();\n            }\n            Application.Exit();\n        }\n\n        private void phase0ToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            phase0ToolStripMenuItem.Checked = true;\n            phase1ToolStripMenuItem.Checked = false;\n            phase2ToolStripMenuItem.Checked = false;\n            phase3ToolStripMenuItem.Checked = false;\n            RebootWithAlignment(0);\n        }\n\n        private void phase1ToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            phase0ToolStripMenuItem.Checked = false;\n            phase1ToolStripMenuItem.Checked = true;\n            phase2ToolStripMenuItem.Checked = false;\n            phase3ToolStripMenuItem.Checked = false;\n            RebootWithAlignment(1);\n        }\n\n        private void phase2ToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            phase0ToolStripMenuItem.Checked = false;\n            phase1ToolStripMenuItem.Checked = false;\n            phase2ToolStripMenuItem.Checked = true;\n            phase3ToolStripMenuItem.Checked = false;\n            RebootWithAlignment(2);\n        }\n\n        private void phase3ToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            phase0ToolStripMenuItem.Checked = false;\n            phase1ToolStripMenuItem.Checked = false;\n            phase2ToolStripMenuItem.Checked = false;\n            phase3ToolStripMenuItem.Checked = true;\n            RebootWithAlignment(3);\n        }\n\n        private void RebootWithAlignment(byte Alignment)\n        {\n            if (EMU != null)\n            {\n                Emulator Emu2 = new Emulator();\n                Emu2.Cart = EMU.Cart;\n                Emu2.Cart.Emu = Emu2;\n                EMU = Emu2;\n                EMU.PPUClock = Alignment;\n                EMU.CPUClock = 0;\n                EMU.PPU_DecodeSignal = settings_ntsc;\n                EMU.PPU_ShowRawNTSCSignal = settings_ntscRaw;\n                EMU.PPU_ShowScreenBorders = settings_border;\n            }\n            settings_alignment = Alignment;\n        }\n\n        private void trueToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            falseToolStripMenuItem.Checked = false;\n            showRawSignalsToolStripMenuItem.Checked = false;\n            trueToolStripMenuItem.Checked = true;\n            if (EMU != null)\n            {\n                EMU.PPU_DecodeSignal = true;\n                EMU.PPU_ShowRawNTSCSignal = false;\n            }\n            settings_ntsc = true;\n            settings_ntscRaw = false;\n        }\n\n        private void falseToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            trueToolStripMenuItem.Checked = false;\n            showRawSignalsToolStripMenuItem.Checked = false;\n            falseToolStripMenuItem.Checked = true;\n            if (EMU != null)\n            {\n                EMU.PPU_DecodeSignal = false;\n                EMU.PPU_ShowRawNTSCSignal = false;\n            }\n            settings_ntsc = false;\n            settings_ntscRaw = false;\n        }\n\n        private void showRawSignalsToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            trueToolStripMenuItem.Checked = false;\n            showRawSignalsToolStripMenuItem.Checked = true;\n            falseToolStripMenuItem.Checked = false;\n            if (EMU != null)\n            {\n                EMU.PPU_DecodeSignal = true;\n                EMU.PPU_ShowRawNTSCSignal = true;\n            }\n            settings_ntsc = true;\n            settings_ntscRaw = true;\n        }\n\n        public void ResizeWindow(int scale)\n        {\n            int w = 256;\n            int h = 240;\n            if (EMU != null)\n            {\n                if (EMU.PPU_ShowScreenBorders)\n                {\n                    w = 341;\n                    h = 262;\n                }\n            }\n\n            Size pbs = new Size();\n            pbs.Width = w * scale;\n            pbs.Height = h * scale;\n            Size ws = new Size();\n            ws.Width = w * scale + 16;\n            ws.Height = h * scale + 66;\n            MinimumSize = ws;\n            MaximumSize = ws;\n            pb_Screen.Size = pbs;\n            Width = ws.Width;\n            Height = ws.Height;\n        }\n\n        int ScreenMult = 1;\n        private void xToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            ScreenMult = 1;\n            ResizeWindow(1);\n        }\n\n        private void xToolStripMenuItem1_Click(object sender, EventArgs e)\n        {\n            ScreenMult = 2;\n            ResizeWindow(2);\n        }\n\n        private void xToolStripMenuItem2_Click(object sender, EventArgs e)\n        {\n            ScreenMult = 3;\n            ResizeWindow(3);\n        }\n\n        private void xToolStripMenuItem3_Click(object sender, EventArgs e)\n        {\n            ScreenMult = 4;\n            ResizeWindow(4);\n        }\n\n        private void xToolStripMenuItem4_Click(object sender, EventArgs e)\n        {\n            ScreenMult = 5;\n            ResizeWindow(5);\n        }\n\n        private void xToolStripMenuItem5_Click(object sender, EventArgs e)\n        {\n            ScreenMult = 6;\n            ResizeWindow(6);\n        }\n\n        private void xToolStripMenuItem6_Click(object sender, EventArgs e)\n        {\n            ScreenMult = 7;\n            ResizeWindow(7);\n        }\n\n        private void xToolStripMenuItem7_Click(object sender, EventArgs e)\n        {\n            ScreenMult = 8;\n            ResizeWindow(8);\n        }\n\n        private void traceLoggerToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            if(TraceLogger != null)\n            {\n                TraceLogger.Focus();\n                return;\n            }\n            TraceLogger = new TriCTraceLogger();\n            TraceLogger.MainGUI = this;\n            TraceLogger.Init();\n            TraceLogger.Show();\n            TraceLogger.Location = Location;\n        }\n        bool Pending_ShowScreenBorders;\n        private void trueToolStripMenuItem1_Click(object sender, EventArgs e)\n        {\n            toolstrip_ViewBorders_False.Checked = false;\n            toolstrip_ViewBorders_True.Checked = true;\n            if (EMU != null)\n            {\n                Pending_ShowScreenBorders = true;\n            }\n            settings_border = true;\n        }\n        bool Pending_HideScreenBorders;\n        private void falseToolStripMenuItem1_Click(object sender, EventArgs e)\n        {\n            toolstrip_ViewBorders_False.Checked = true;\n            toolstrip_ViewBorders_True.Checked = false;\n            if (EMU != null)\n            {\n                Pending_HideScreenBorders = true;\n            }\n            settings_border = false;\n        }\n\n        private void nametableViewerToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            if(NametableViewer != null)\n            {\n                NametableViewer.Focus();\n                return;\n            }\n            NametableViewer = new TriCNTViewer();\n            NametableViewer.MainGUI = this;\n            NametableViewer.Show();\n            NametableViewer.Location = Location;\n        }\n\n        private void hexEditorToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            if (HexExditor != null)\n            {\n                HexExditor.Focus();\n                return;\n            }\n            HexExditor = new TriCHexEditor();\n            HexExditor.MainGUI = this;\n            HexExditor.Show();\n            HexExditor.Location = Location;\n        }\n\n        List<Byte> Savestate = new List<byte>();\n        bool PendingSaveState = false;\n        private void saveStateToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            PendingSaveState = true;\n        }\n        bool PendingLoadState = false;\n        private void loadStateToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            if (TasTimeline == null) // this would cause a desync otherwise, so forcefully prevent this.\n            {\n                PendingLoadState = true;\n            }\n        }\n\n        private void tASTimelineToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            if(TasTimeline != null)\n            {\n                TasTimeline.Focus();\n                return;\n            }\n            bool EMUExists = (EMU != null);\n            if (!EMUExists)\n            {\n                string InitDirectory = AppDomain.CurrentDomain.BaseDirectory;\n                if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @\"roms\\\"))\n                {\n                    InitDirectory += @\"roms\\\";\n                }\n                OpenFileDialog ofd = new OpenFileDialog()\n                {\n                    FileName = \"\",\n                    Filter = \"NES ROM files (*.nes)|*.nes\",\n                    Title = \"Select file\",\n                    InitialDirectory = InitDirectory\n                };\n\n                if (ofd.ShowDialog() == DialogResult.OK)\n                {\n                    if (EmuClock != null)\n                    {\n                        cancel.Cancel();\n                        EmuClock.Join();\n                    }\n                    filePath = ofd.FileName;\n                    FDS = Path.GetExtension(ofd.FileName) == \".fds\";\n                    TasTimeline = new TriCTASTimeline(this);\n                    TasTimeline.Show();\n                    TasTimeline.Location = Location;\n                }\n            }\n            else\n            {\n                TasTimeline = new TriCTASTimeline(this);\n                TasTimeline.Show();\n                TasTimeline.Location = Location;\n            }\n        }\n\n        public List<ushort> ParseTasFile(string TasFilePath, out List<bool> Resets)\n        {\n            // determine file type\n            string extension = Path.GetExtension(TasFilePath);\n            // create list of inputs from the tas file, and make any settings changes if needed.\n            byte[] ByteArray = File.ReadAllBytes(TasFilePath);\n            List<ushort> TASInputs = new List<ushort>(); // Low byte is player 1, High byte is player 2.\n            List<bool> TASResets = new List<bool>();\n\n            switch (extension)\n            {\n                case \".bk2\":\n                case \".tasproj\":\n                    {\n                        // .bk2 files are actually just .zip files!\n                        // Let's yoink \"Input Log.txt\" from this .bk2 file\n                        StringReader InputLog = new StringReader(new string(new StreamReader(ZipFile.OpenRead(TasFilePath).Entries.Where(x => x.Name.Equals(\"Input Log.txt\", StringComparison.InvariantCulture)).FirstOrDefault().Open(), Encoding.UTF8).ReadToEnd().ToArray()));\n                        // now to parse the input log!\n                        InputLog.ReadLine(); // \"[Input]\"\n                        string key = InputLog.ReadLine(); // \"LogKey: ... \"\n                        bool Bk2_Port1 = key.Contains(\"P1\");\n                        bool Bk2_Port2 = key.Contains(\"P2\");\n                        string ln = InputLog.ReadLine();\n                        ushort u = 0;\n                        while (ln != null && ln.Length > 3)\n                        {\n                            int pipeIndex = ln.Substring(1, ln.Length - 1).IndexOf('|') + 1;\n                            char[] lnCharArray = ln.ToCharArray();\n                            bool reset = lnCharArray[pipeIndex - 1] == 'r';\n                            u = 0;\n                            if (Bk2_Port1)\n                            {\n                                u |= (ushort)(lnCharArray[pipeIndex + 1] == 'U' ? 0x08 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 2] == 'D' ? 0x04 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 3] == 'L' ? 0x02 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 4] == 'R' ? 0x01 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 5] == 'S' ? 0x10 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 6] == 's' ? 0x20 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 7] == 'B' ? 0x40 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 8] == 'A' ? 0x80 : 0);\n                            }\n                            else if (Bk2_Port2) // Are there any NES TASes that only feature controller 2?\n                            {\n                                u |= (ushort)(lnCharArray[pipeIndex + 1] == 'U' ? 0x0800 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 2] == 'D' ? 0x0400 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 3] == 'L' ? 0x0200 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 4] == 'R' ? 0x0100 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 5] == 'S' ? 0x1000 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 6] == 's' ? 0x2000 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 7] == 'B' ? 0x4000 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 8] == 'A' ? 0x8000 : 0);\n                            }\n                            if (Bk2_Port1 && Bk2_Port2)\n                            {\n                                pipeIndex = ln.Substring(pipeIndex + 1, ln.Length - 1 - pipeIndex).IndexOf('|') + pipeIndex + 1;\n                                u |= (ushort)(lnCharArray[pipeIndex + 1] == 'U' ? 0x0800 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 2] == 'D' ? 0x0400 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 3] == 'L' ? 0x0200 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 4] == 'R' ? 0x0100 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 5] == 'S' ? 0x1000 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 6] == 's' ? 0x2000 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 7] == 'B' ? 0x4000 : 0);\n                                u |= (ushort)(lnCharArray[pipeIndex + 8] == 'A' ? 0x8000 : 0);\n                            }\n                            TASInputs.Add(u);\n                            TASResets.Add(reset);\n                            ln = InputLog.ReadLine();\n                            if (ln == \"[/Input]\")\n                            {\n                                break;\n                            }\n                        }\n                    }\n                    break;\n                case \".fm2\":\n                    {\n                        // change the alignment to use FCEUX's\n                        // header info of varying size\n                        // Every line of a header ends in $0A\n                        // Every header section is named. Example: $0A \"romFileName\"\n                        // Since the input log begins with \"|\" and none of the header section names begin with \"|\", I can assume $0A\"|\" is the start of the input log\n                        bool fm2_UsePort0 = false;\n                        bool fm2_UsePort1 = false;\n\n                        int i = 0;\n                        while (i < ByteArray.Length)\n                        {\n                            // parse for \"port0 ?\"\n                            if (ByteArray[i] == 0x0A &&\n                                ByteArray[i + 1] == 0x70 &&\n                                ByteArray[i + 2] == 0x6F &&\n                                ByteArray[i + 3] == 0x72 &&\n                                ByteArray[i + 4] == 0x74 &&\n                                ByteArray[i + 5] == 0x30 &&\n                                ByteArray[i + 6] == 0x20\n                                )\n                            {\n                                fm2_UsePort0 = ByteArray[i + 7] == 0x31;\n                            }\n                            // parse for \"port1 ?\"\n                            if (ByteArray[i] == 0x0A &&\n                                ByteArray[i + 1] == 0x70 &&\n                                ByteArray[i + 2] == 0x6F &&\n                                ByteArray[i + 3] == 0x72 &&\n                                ByteArray[i + 4] == 0x74 &&\n                                ByteArray[i + 5] == 0x31 &&\n                                ByteArray[i + 6] == 0x20\n                                )\n                            {\n                                fm2_UsePort1 = ByteArray[i + 7] == 0x31;\n                            }\n\n                            if (ByteArray[i] == 0x0A && ByteArray[i + 1] == 0x7C)\n                            {\n                                break;\n                            }\n                            i++;\n                        }\n\n                        ushort u = 0;\n\n                        int Port0Index = 0;\n                        int Port1Index = 0;\n\n                        while (i < ByteArray.Length)\n                        {\n                            if (ByteArray[i] == 0x0A)\n                            {\n                                if (i == ByteArray.Length - 1)\n                                {\n                                    break;\n                                }\n                                if (ByteArray[i + 1] == 0x0A)\n                                {\n                                    // The .fm2 TAS file format supports empty rows. Formatting quirk?\n                                    i++;\n                                    continue;\n                                }\n                                if (ByteArray[i + 1] == 0x23)\n                                {\n                                    // The .fm2 TAS file format supports comments, in the following format:\n                                    //\\n### Comment\n                                    // so basically, check for `#` as the next character.\n\n                                    // And now we skip until the next new line.\n                                    i++;\n                                    continue;\n                                }\n                                bool reset = (ByteArray[i + 2] & 1) == 1;\n                                if (fm2_UsePort0)\n                                {\n                                    Port0Index = i + 4;\n                                    if (fm2_UsePort1)\n                                    {\n                                        Port1Index = i + 0xD;\n                                    }\n                                }\n                                else if (fm2_UsePort1)\n                                {\n                                    Port1Index = i + 0x6;\n                                }\n\n                                u = 0;\n                                if (fm2_UsePort0)\n                                {\n                                    u |= (ushort)(ByteArray[Port0Index] == 0x2E ? 0 : 1);\n                                    u |= (ushort)(ByteArray[Port0Index + 1] == 0x2E ? 0 : 2);\n                                    u |= (ushort)(ByteArray[Port0Index + 2] == 0x2E ? 0 : 4);\n                                    u |= (ushort)(ByteArray[Port0Index + 3] == 0x2E ? 0 : 8);\n                                    u |= (ushort)(ByteArray[Port0Index + 4] == 0x2E ? 0 : 0x10);\n                                    u |= (ushort)(ByteArray[Port0Index + 5] == 0x2E ? 0 : 0x20);\n                                    u |= (ushort)(ByteArray[Port0Index + 6] == 0x2E ? 0 : 0x40);\n                                    u |= (ushort)(ByteArray[Port0Index + 7] == 0x2E ? 0 : 0x80);\n                                }\n                                if (fm2_UsePort1)\n                                {\n                                    u |= (ushort)(ByteArray[Port1Index] == 0x2E ? 0 : 0x100);\n                                    u |= (ushort)(ByteArray[Port1Index + 1] == 0x2E ? 0 : 0x200);\n                                    u |= (ushort)(ByteArray[Port1Index + 2] == 0x2E ? 0 : 0x400);\n                                    u |= (ushort)(ByteArray[Port1Index + 3] == 0x2E ? 0 : 0x800);\n                                    u |= (ushort)(ByteArray[Port1Index + 4] == 0x2E ? 0 : 0x1000);\n                                    u |= (ushort)(ByteArray[Port1Index + 5] == 0x2E ? 0 : 0x2000);\n                                    u |= (ushort)(ByteArray[Port1Index + 6] == 0x2E ? 0 : 0x4000);\n                                    u |= (ushort)(ByteArray[Port1Index + 7] == 0x2E ? 0 : 0x8000);\n                                }\n                                TASInputs.Add(u);\n                                TASResets.Add(reset);\n\n                            }\n                            i++;\n                        }\n                    }\n                    break;\n                case \".fm3\":\n                    {\n                        // similar to fm2, this has a header of varying length.\n                        // But it also contains significantly more metadata after the input log.\n                        // we need to parse $0A\"length \"\n                        bool fm3_UsePort0 = false;\n                        bool fm3_UsePort1 = false;\n                        int i = 0;\n                        while (i < ByteArray.Length)\n                        {\n                            if (ByteArray[i] == 0x0A)\n                            {\n                                if (ByteArray[i] == 0x0A &&\n                                ByteArray[i + 1] == 0x70 &&\n                                ByteArray[i + 2] == 0x6F &&\n                                ByteArray[i + 3] == 0x72 &&\n                                ByteArray[i + 4] == 0x74 &&\n                                ByteArray[i + 5] == 0x30 &&\n                                ByteArray[i + 6] == 0x20\n                                )\n                                {\n                                    fm3_UsePort0 = ByteArray[i + 7] == 0x31;\n                                }\n                                // parse for \"port1 ?\"\n                                if (ByteArray[i] == 0x0A &&\n                                    ByteArray[i + 1] == 0x70 &&\n                                    ByteArray[i + 2] == 0x6F &&\n                                    ByteArray[i + 3] == 0x72 &&\n                                    ByteArray[i + 4] == 0x74 &&\n                                    ByteArray[i + 5] == 0x31 &&\n                                    ByteArray[i + 6] == 0x20\n                                    )\n                                {\n                                    fm3_UsePort1 = ByteArray[i + 7] == 0x31;\n                                }\n                                // check if this is the header info for \"length\"\n                                if (ByteArray[i] == 0x0A)\n                                {\n                                    if (ByteArray[i + 1] == 0x6C &&\n                                        ByteArray[i + 2] == 0x65 &&\n                                        ByteArray[i + 3] == 0x6E &&\n                                        ByteArray[i + 4] == 0x67 &&\n                                        ByteArray[i + 5] == 0x74 &&\n                                        ByteArray[i + 6] == 0x68 &&\n                                        ByteArray[i + 7] == 0x20)\n                                    {\n                                        // okay, so the length is in ascii...\n                                        // let's figure out where the next $0A character is\n                                        int next0A = i + 8;\n                                        while (next0A < ByteArray.Length)\n                                        {\n                                            if (ByteArray[next0A] == 0x0A)\n                                            {\n                                                break;\n                                            }\n                                            next0A++;\n                                        }\n                                        // okay, so the string from i+8 though next0A is the length.\n                                        byte[] StringArray = new byte[next0A - (i + 8)];\n                                        Array.Copy(ByteArray, i + 8, StringArray, 0, StringArray.Length);\n                                        int InputLogLength = int.Parse(Encoding.Default.GetString(StringArray));\n                                        i = next0A + 2;\n                                        int tempMul = 1;\n                                        if (fm3_UsePort0) { tempMul++; }\n                                        if (fm3_UsePort1) { tempMul++; }\n                                        int InputLogByteLength = InputLogLength * tempMul;\n                                        // first byte is always zero?\n                                        // next byte is controller 1 (if enabled)\n                                        // next byte is controller 2 (if enabled)\n                                        ushort u = 0;\n                                        while (i < next0A + 2 + InputLogByteLength)\n                                        {\n                                            bool reset = (ByteArray[i] & 1) == 1;\n                                            i++;// dummy byte (?)\n                                            u = 0;\n                                            if (fm3_UsePort0) { u = ByteArray[i]; i++; }\n                                            if (fm3_UsePort1) { u |= (ushort)(ByteArray[i] << 8); i++; }\n                                            TASInputs.Add(u);\n                                            TASResets.Add(reset);\n                                        }\n\n                                    }\n\n                                }\n\n                            }\n                            i++;\n\n                        }\n\n\n\n                    }\n                    break;\n                case \".fmv\":\n                    {\n                        int i = 0x90; // there's a 144 byte header\n                        bool fmv_UseController2 = (ByteArray[5] & 0b00010000) != 0;\n                        if (fmv_UseController2)\n                        {\n                            while (i < ByteArray.Length)\n                            {\n                                ushort u = (ushort)(FamtasiaInput2Standard(ByteArray[i]) | (FamtasiaInput2Standard(ByteArray[i + 1]) << 8));\n                                TASInputs.Add(u);\n                                i += 2;\n                            }\n                        }\n                        else\n                        {\n                            while (i < ByteArray.Length)\n                            {\n                                TASInputs.Add(FamtasiaInput2Standard(ByteArray[i]));\n                                i++;\n                            }\n                        }\n                    }\n                    break;\n                case \".3c2\":\n                    {\n                        // The .3c2 format is pretty much identical to the .r08 file format, but with a 1-byte header.\n                        // Bit 0: 0 = Latch Filtering. 1 = Clock Filtering.\n                        // Bit 1: 0 = Only controller 1. 1 = Controller 1 and controller 2.\n                        // Bit 2: 0 = No reset button. 1 = The reset button is used in this TAS.\n\n                        bool UseController2 = (ByteArray[0] & 2) != 0;\n                        bool UseReset = (ByteArray[0] & 4) != 0;\n\n                        byte b = 0;\n                        byte b2 = 0;\n                        int i = 1;\n                        while (i < ByteArray.Length)\n                        {\n                            b = ByteArray[i];\n                            i++;\n                            if (UseController2)\n                            {\n                                b2 = ByteArray[i];\n                                i++;\n                            }\n                            TASInputs.Add((ushort)(b | (b2 << 8)));\n                            if (UseReset)\n                            {\n                                bool res = (ByteArray[i] & 0x80) == 0x80; // I use bit 7 for the reset button. (bit 0 is for lag frames in the .3c3 format.)\n                                TASResets.Add(res);\n                                i++;\n                            }\n                        }\n                        TASInputs.Add(0); // append a zero to the end for safe measure.\n                    }\n                    break;\n                case \".r08\":\n                    {\n                        // the .r08 file format is conveniently already in the format I want for my emulator.\n                        byte b = 0;\n                        byte b2 = 0;\n                        int i = 0;\n                        while (i < ByteArray.Length)\n                        {\n                            b = ByteArray[i];\n                            b2 = ByteArray[i + 1];\n                            TASInputs.Add((ushort)(b | (b2 << 8)));\n                            i += 2;\n                        }\n                        TASInputs.Add(0); // append a zero to the end for safe measure.\n                    }\n                    break;\n                case \".3c3\":\n                    {\n                        // .3c3 is the format for my TAS timeline.\n                        // The big differences are:\n                        // - .3c3 saves the savestate information\n                        // - .3c3 saves the \"lag frame\" information as well. (So every frame is 3 bytes now.)\n\n                        // .3c3 has a 16 byte header.\n                        // It's just little-endian 32-bit integers, and the same 1-byte header used in .3c2's.\n                        // The first one determines how many bytes are in every savestate.\n                        // the second one determinines how many frames there are in this TAS.\n                        // I guess that means there's a limit of 2,147,483,647 frames in a .3c3 TAS file. God help me if I ever feel compelled to challenge this.\n                        // Then there's a handful of unused bytes. ByteArray[15] is the same format as the 1-byte header used in 3c2's.\n                        // Bit 0: 0 = Latch Filtering. 1 = Clock Filtering.\n                        // Bit 1: 0 = Only controller 1. 1 = Controller 1 and controller 2.\n                        // Bit 2: 0 = No reset button. 1 = The reset button is used in this TAS.\n\n\n                        int SavestateLength = ByteArray[0] | (ByteArray[1] << 8) | (ByteArray[2] << 16) | (ByteArray[3] << 24);\n                        int rerecords = ByteArray[4] | (ByteArray[5] << 8) | (ByteArray[6] << 16) | (ByteArray[7] << 24);\n                        int frameCount = ByteArray[8] | (ByteArray[9] << 8) | (ByteArray[10] << 16) | (ByteArray[11] << 24);\n\n                        bool UseController2 = (ByteArray[15] & 2) != 0;\n                        bool UseReset = (ByteArray[15] & 4) != 0;\n\n                        List<List<byte>> saveStates = new List<List<byte>>();\n                        List<List<byte>> saveStates2 = new List<List<byte>>();\n                        List<bool> lagFrames = new List<bool>();\n\n                        byte b = 0;\n                        byte b2 = 0;\n                        int i = 16;\n                        while (i < frameCount * 3 + 16)\n                        {\n                            b = ByteArray[i];\n                            i++;\n                            if (UseController2)\n                            {\n                                b2 = ByteArray[i];\n                                i++;\n                            }\n                            TASInputs.Add((ushort)(b | (b2 << 8)));\n                            bool lagframe = (ByteArray[i] & 1) == 1; // I use bit 0 for the lag frame info.\n                            lagFrames.Add(lagframe);\n                            if (UseReset)\n                            {\n                                bool res = (ByteArray[i] & 0x80) == 0x80; // I use bit 7 for the reset button.\n                                TASResets.Add(res);\n                            }\n                            i++;\n                            saveStates.Add(new List<byte>());\n                            saveStates2.Add(new List<byte>());\n\n                        }\n\n                        // and from here until you reach the end of the file, the data is arranged in the following format:\n                        // [32-bit int declaring the frame number, and 'n' bytes for the save state at that frame.]\n\n                        while (i < ByteArray.Length)\n                        {\n                            // read the 4 byte header.\n                            int frameIndex = ByteArray[i] | (ByteArray[i + 1] << 8) | (ByteArray[i + 2] << 16) | (ByteArray[i + 3] << 24);\n                            i += 4;\n                            int j = 0;\n                            while (j < SavestateLength)\n                            {\n                                saveStates[frameIndex].Add(ByteArray[i]);\n                                i++;\n                                j++;\n                            }\n                        }\n\n                        if (TasTimeline != null)\n                        {\n                            TriCTASTimeline.TimelineSavestates = saveStates;\n                            TriCTASTimeline.TimelineTempSavestates = saveStates2; // the empty list.\n                            TriCTASTimeline.LagFrames = lagFrames;\n                            TasTimeline.highestFrameEmulatedEver = frameCount - 1;\n                            TasTimeline.frameEmulated = frameCount - 1;\n                            TasTimeline.Rerecords = rerecords;\n                        }\n                    }\n                    break;\n                    // TODO: ask if the .tasd file format is a thing yet\n            }\n            if (TASResets.Count == 0) // If not using Resets, we still want to initialize the Resets list, in case they are added to the TAS timeline at a later point.\n            {\n                TASResets = new List<bool>(new bool[TASInputs.Count]);\n            }\n\n            Resets = TASResets;\n            return TASInputs;\n        }\n        byte FamtasiaInput2Standard(byte input)\n        {\n            //famtasia format is SsABDULR\n            byte b0 = (byte)(input & 0x8);\n            byte b1 = (byte)(input & 0x4);\n            byte b2 = (byte)(input & 0xC0);\n            byte b3 = (byte)(input & 0x30);\n            b0 >>= 1;\n            b1 <<= 1;\n            byte b4 = (byte)(b2 & 0x80);\n            byte b5 = (byte)(b2 & 0x40);\n            b4 >>= 1;\n            b5 <<= 1;\n            b2 = (byte)(b4 | b5);\n            b2 >>= 2;\n            b3 <<= 2;\n            byte b = (byte)(b2 | b3 | b0 | b1 | (input & 0x3));\n            return b;\n        }\n\n        public void CreateTASTimelineEmulator()\n        {\n            if (EmuClock != null)\n            {\n                cancel.Cancel();\n                EmuClock.Join();\n            }\n            if (EMU != null)\n            {\n                EMU.Dispose();\n                GC.Collect();\n            }\n            Timeline_Paused = true;\n            EMU = new Emulator();\n            EMU.PPU_DecodeSignal = settings_ntsc;\n            EMU.PPU_ShowRawNTSCSignal = settings_ntscRaw;\n            EMU.PPU_ShowScreenBorders = settings_border;\n            EMU.PPUClock = settings_alignment;\n            if (!LoadROM(filePath)) { return; }\n\n            cancel = new CancellationTokenSource();\n            EmuClock = new Thread(() => ClockTimelineEmulator(cancel.Token));\n            EmuClock.SetApartmentState(ApartmentState.STA);\n            EmuClock.IsBackground = true;\n            EmuClock.Start();\n        }\n\n        public bool Timeline_PendingPause;\n        public bool Timeline_PendingResume;\n        public bool Timeline_Paused;\n        public bool Timeline_PendingFrameAdvance;\n        public bool Timeline_PendingLoadState;\n        public int Timeline_PendingFrameNumber;\n        public bool Timeline_PendingHardReset;\n        public bool Timeline_PendingArbitrarySavestate;\n        public bool Timeline_AutoPlayUntilTarget;\n        public int Timeline_AutoPlayTarget;\n        public bool Timeline_PendingMouseDown;\n        public bool Timeline_PendingMouseHeld;\n        public bool Timeline_PendingResetScreen;\n        public bool Timeline_PendingClockFiltering;\n\n        public bool Timeline_HotkeyHeld_RShoulder;\n        public bool Timeline_HotkeyHeld_RTrigger;\n        public bool Timeline_HotkeyHeld_LTrigger;\n\n        public List<byte> Timeline_LoadState;\n        void ClockTimelineEmulator(CancellationToken ct)\n        {\n\n            while (!ct.IsCancellationRequested)\n            {\n                if (Timeline_PendingHardReset)\n                {\n                    Timeline_PendingHardReset = false;\n                    if (EMU != null)\n                    {\n                        EMU.Dispose();\n                        GC.Collect();\n                    }\n                    EMU = new Emulator();\n                    EMU.PPU_DecodeSignal = settings_ntsc;\n                    EMU.PPU_ShowRawNTSCSignal = settings_ntscRaw;\n                    EMU.PPU_ShowScreenBorders = settings_border;\n                    EMU.PPUClock = settings_alignment;\n                    if (!LoadROM(filePath)) { return; }\n\n                    if (Timeline_PendingClockFiltering)\n                    {\n                        Timeline_PendingClockFiltering = false;\n                        EMU.TASTimelineClockFiltering = true;\n                    }\n                }\n                if (Timeline_PendingArbitrarySavestate)\n                {\n                    Timeline_PendingArbitrarySavestate = false; // pretty much only ever set when loading a TAS.\n                    List<byte> state = EMU.SaveState();\n                    TriCTASTimeline.TimelineSavestates.Add(state);\n                    TriCTASTimeline.TimelineTempSavestates.Add(new List<byte>());\n                }\n\n                bool[] ControllerHotkeys = OtherControllerHotkeys();\n\n                if (!Timeline_HotkeyHeld_RShoulder && ControllerHotkeys[0])\n                {\n                    Timeline_PendingPause = !Timeline_Paused;\n                    Timeline_PendingResume = Timeline_Paused;\n                }\n\n                if ((ControllerHotkeys[2] && ControllerHotkeys[1]) || (!Timeline_HotkeyHeld_RTrigger && ControllerHotkeys[2]))\n                {\n                    Timeline_PendingFrameAdvance = true;\n                    Timeline_PendingPause = !Timeline_Paused;\n                }\n                bool rewinding = false;\n                if ((ControllerHotkeys[3] && ControllerHotkeys[1]) || (!Timeline_HotkeyHeld_LTrigger && ControllerHotkeys[3]))\n                {\n                    TasTimeline.FrameRewind();\n                    Timeline_PendingPause = !Timeline_Paused;\n                    rewinding = true;\n                }\n\n                Timeline_HotkeyHeld_RShoulder = ControllerHotkeys[0];\n                Timeline_HotkeyHeld_RTrigger = ControllerHotkeys[2];\n                Timeline_HotkeyHeld_LTrigger = ControllerHotkeys[3];\n\n                if (Timeline_PendingPause)\n                {\n                    Timeline_PendingPause = false;\n                    Timeline_Paused = true;\n                    TasTimeline.ChangePlayPauseButtonText(\"Paused\");\n                }\n                if (Timeline_PendingResume)\n                {\n                    Timeline_PendingResume = false;\n                    Timeline_Paused = false;\n                    TasTimeline.ChangePlayPauseButtonText(\"Running\");\n                }\n                if (Timeline_PendingMouseDown)\n                {\n                    Timeline_PendingMouseDown = false;\n                    TasTimeline.TimelineMouseDownEvent();\n                }\n                if (Timeline_PendingMouseHeld)\n                {\n                    Timeline_PendingMouseHeld = false;\n                    TasTimeline.TimelineMouseHeldEvent();\n                }\n                if (Timeline_PendingLoadState)\n                {\n                    Timeline_PendingLoadState = false;\n                    PendingLoadState = true;\n                    Savestate = Timeline_LoadState;\n                    TasTimeline.frameIndex = Timeline_PendingFrameNumber;\n                }\n                if (Timeline_PendingResetScreen)\n                {\n                    Timeline_PendingResetScreen = false;\n                    pb_Screen.Invoke(new MethodInvoker(\n                    delegate ()\n                    {\n                        Bitmap b = new Bitmap(pb_Screen.Image);\n                        for (int x = 0; x < b.Width; x++) { for (int y = 0; y < b.Height; y++) { b.SetPixel(x, y, Color.Black); } }\n                        pb_Screen.Image = b;\n                        pb_Screen.Update();\n                    }));\n                }\n                bool FrameAdvance = false;\n                if (Timeline_PendingFrameAdvance)\n                {\n                    Timeline_PendingFrameAdvance = false;\n                    FrameAdvance = true;\n                }\n\n                if (Timeline_AutoPlayUntilTarget && TasTimeline.frameIndex >= Timeline_AutoPlayTarget)\n                {\n                    Timeline_AutoPlayUntilTarget = false;\n                }\n\n                RunUpkeep();\n                if (Timeline_Paused && !FrameAdvance && !Timeline_AutoPlayUntilTarget)\n                {\n                    Thread.Sleep(50);\n                }\n                else\n                {\n                    if (TasTimeline.frameIndex == TriCTASTimeline.TimelineSavestates.Count)\n                    {\n                        // create a savestate for the previous frame.\n                        if (TasTimeline.SavestateEveryFrame())\n                        {\n                            List<byte> state = EMU.SaveState();\n                            TriCTASTimeline.TimelineSavestates.Add(state);\n                            TasTimeline.SavestateLength = state.Count;\n                        }\n                        else\n                        {\n                            List<byte> state = new List<byte>();\n                            TriCTASTimeline.TimelineSavestates.Add(state);\n                        }\n                        if (TriCTASTimeline.TimelineSavestates[TasTimeline.frameIndex].Count > 0)\n                        {\n                            // if this savestate is not empty\n                            List<byte> state = new List<byte>();\n                            TriCTASTimeline.TimelineTempSavestates.Add(state);\n                            TasTimeline.TrimTempSavestates();\n                            //TriCTASTimeline.TEMPRerecordTracker.Add(TasTimeline.Rerecords);\n                        }\n                        else\n                        {\n                            // if this savestate is empty\n                            List<byte> state = EMU.SaveState();\n                            TriCTASTimeline.TimelineTempSavestates.Add(state);\n                            TasTimeline.TrimTempSavestates();\n                            //TriCTASTimeline.TEMPRerecordTracker.Add(TasTimeline.Rerecords);\n                        }\n                    }\n                    else if (TasTimeline.frameIndex < TriCTASTimeline.TimelineTempSavestates.Count && TriCTASTimeline.TimelineTempSavestates[TasTimeline.frameIndex].Count == 0)\n                    {\n                        List<byte> state = EMU.SaveState();\n                        TriCTASTimeline.TimelineTempSavestates[TasTimeline.frameIndex] = state;\n                        TasTimeline.TrimTempSavestates();\n                    }\n\n                    if (TasTimeline.RecordInputs() && !rewinding)\n                    {\n                        byte realtimeInputs = RealtimeInputs();\n                        if (TasTimeline.Player2())\n                        {\n                            EMU.ControllerPort2 = realtimeInputs;\n                            EMU.ControllerPort1 = 0;\n                        }\n                        else\n                        {\n                            EMU.ControllerPort1 = realtimeInputs;\n                            EMU.ControllerPort2 = 0;\n                        }\n                        ushort rimputs = (ushort)((EMU.ControllerPort2 << 8) | EMU.ControllerPort1);\n                        TriCTASTimeline.Inputs[TasTimeline.frameIndex] = rimputs;\n                        int row = TasTimeline.frameIndex - TasTimeline.TopFrame;\n                        if (row >= 0 && row < 40)\n                        {\n                            TasTimeline.RecalculateTimelineRow(row, rimputs);\n                            TasTimeline.RedrawTimelineRow(row, false);\n                        }\n                        if (TasTimeline.frameIndex < TasTimeline.frameEmulated)\n                        {\n                            TasTimeline.MarkStale(TasTimeline.frameIndex);\n                            Timeline_PendingLoadState = false; // the MarkStale() function typically loads a savestate, but we don't want that here.\n                        }\n                    }\n                    else\n                    {\n                        EMU.ControllerPort1 = (byte)(TriCTASTimeline.Inputs[TasTimeline.frameIndex] & 0xFF);\n                        EMU.ControllerPort2 = (byte)((TriCTASTimeline.Inputs[TasTimeline.frameIndex] & 0xFF00) >> 8);\n                    }\n\n                    EMU._CoreFrameAdvance();\n                    RunPostFramePhase();\n                    if (TasTimeline.frameIndex < TriCTASTimeline.Resets.Count && TriCTASTimeline.Resets[TasTimeline.frameIndex])\n                    {\n                        EMU.Reset();\n                    }\n\n                    if (!EMU.TASTimelineClockFiltering || !EMU.LagFrame)\n                    {\n                        TasTimeline.FrameAdvance();\n                    }\n                    else\n                    {\n                        //Timeline_PendingFrameAdvance = true; // keep running until a non-lag frame.\n                    }\n                }\n            }\n        }\n\n        public bool[] OtherControllerHotkeys()\n        {\n            bool[] joystickButtons = new bool[4];\n\n            int c = SDL.SDL_NumJoysticks();\n            if (c != 0)\n            {\n                SDL.SDL_GameControllerUpdate();\n\n                joystickButtons[0] = SDL.SDL_GameControllerGetButton(gameControllerPrt, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) != 0;\n                joystickButtons[1] = SDL.SDL_GameControllerGetButton(gameControllerPrt, SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSHOULDER) != 0;\n                joystickButtons[2] = SDL.SDL_GameControllerGetAxis(gameControllerPrt, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERRIGHT) > 0.2;\n                joystickButtons[3] = SDL.SDL_GameControllerGetAxis(gameControllerPrt, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERLEFT) > 0.2;\n\n            }\n            else\n            {\n                for (int i = 0; i < 4; i++)\n                {\n                    joystickButtons[i] = false;\n                }\n            }\n            return joystickButtons;\n        }\n\n    }\n\n    /// <summary>\n    /// Inherits from PictureBox; adds Interpolation Mode Setting\n    /// </summary>\n    public class PictureBoxWithInterpolationMode : PictureBox\n    {\n        public InterpolationMode InterpolationMode { get; set; }\n        public PictureBoxWithInterpolationMode()\n        {\n            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);\n            SetStyle(ControlStyles.Opaque, true);\n            SetStyle(ControlStyles.UserPaint, true);\n            SetStyle(ControlStyles.AllPaintingInWmPaint, true);\n        }\n        protected override void OnPaint(PaintEventArgs paintEventArgs)\n        {\n            paintEventArgs.Graphics.PixelOffsetMode = PixelOffsetMode.Half;\n            paintEventArgs.Graphics.InterpolationMode = InterpolationMode;\n            base.OnPaint(paintEventArgs);\n        }\n    }\n\n}\n"
  },
  {
    "path": "forms/TriCNESGUI.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <metadata name=\"menuStrip1.TrayLocation\" type=\"System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n    <value>17, 17</value>\n  </metadata>\n  <metadata name=\"menuStrip1.Locked\" type=\"System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\n    <value>True</value>\n  </metadata>\n  <metadata name=\"pb_Screen.Locked\" type=\"System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\n    <value>True</value>\n  </metadata>\n  <metadata name=\"$this.Locked\" type=\"System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\n    <value>True</value>\n  </metadata>\n  <assembly alias=\"System.Drawing\" name=\"System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\" />\n  <data name=\"$this.Icon\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAA/wAA\n        AP8AAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAA\n        AP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA\n        AAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAA\n        AP8AAAD/AAAA/wAAAP8AAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAAAAAA\n        AAD///////////////////////////////8AAAAAAAAAAAAAAP8AAAD/AAAAAAAAAAD/////////////\n        //////////////////8AAAAAAAAAAAAAAP8AAAD/////////////////////////////////AAAAAAAA\n        AAAAAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//\n        /////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAA\n        AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////\n        ////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA////////\n        //8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAA\n        AP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAA\n        AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//\n        ////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAA\n        AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAA\n        AAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA////////\n        //8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA\n        AAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA\n        AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAA\n        AP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAA\n        AAAAAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//\n        ////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAA\n        AP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA\n        AAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/////////\n        //8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD//////////////////////wAA\n        AP8AAAD/AAAAAAAAAAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAA\n        AAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAAAAD/////////////\n        ////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/////////\n        //8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD///////////8AAAAAAAAAAAAA\n        AAAAAAAA//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////\n        //8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////////8AAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////////\n        /////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////////////////////////wAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAA///////////////////////////////////////////A8D8DwPA/AwPA\n        zAwDwMwMww8A8MMPAPDDDwDwww8A8MMPAPDDDwDwww8A8MMPAPADMDMDAzAzA8/A/A/PwPwP////////\n        //////////////////////////////////8=\n</value>\n  </data>\n</root>"
  },
  {
    "path": "forms/TriCNTViewer.Designer.cs",
    "content": "﻿namespace TriCNES\n{\n    partial class TriCNTViewer\n    {\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private System.ComponentModel.IContainer components = null;\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        /// <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing && (components != null))\n            {\n                components.Dispose();\n            }\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TriCNTViewer));\n            this.pictureBox1 = new System.Windows.Forms.PictureBox();\n            this.cb_ForcePal0ToBackdrop = new System.Windows.Forms.CheckBox();\n            this.cb_ScreenBoundary = new System.Windows.Forms.CheckBox();\n            this.cb_OverlayScreen = new System.Windows.Forms.CheckBox();\n            this.menuStrip1 = new System.Windows.Forms.MenuStrip();\n            this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.screenshotToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();\n            this.menuStrip1.SuspendLayout();\n            this.SuspendLayout();\n            // \n            // pictureBox1\n            // \n            this.pictureBox1.Location = new System.Drawing.Point(0, 21);\n            this.pictureBox1.Name = \"pictureBox1\";\n            this.pictureBox1.Size = new System.Drawing.Size(512, 480);\n            this.pictureBox1.TabIndex = 0;\n            this.pictureBox1.TabStop = false;\n            // \n            // cb_ForcePal0ToBackdrop\n            // \n            this.cb_ForcePal0ToBackdrop.AutoSize = true;\n            this.cb_ForcePal0ToBackdrop.Location = new System.Drawing.Point(13, 508);\n            this.cb_ForcePal0ToBackdrop.Name = \"cb_ForcePal0ToBackdrop\";\n            this.cb_ForcePal0ToBackdrop.Size = new System.Drawing.Size(121, 17);\n            this.cb_ForcePal0ToBackdrop.TabIndex = 1;\n            this.cb_ForcePal0ToBackdrop.Text = \"Use Backdrop Color\";\n            this.cb_ForcePal0ToBackdrop.UseVisualStyleBackColor = true;\n            // \n            // cb_ScreenBoundary\n            // \n            this.cb_ScreenBoundary.AutoSize = true;\n            this.cb_ScreenBoundary.Location = new System.Drawing.Point(12, 531);\n            this.cb_ScreenBoundary.Name = \"cb_ScreenBoundary\";\n            this.cb_ScreenBoundary.Size = new System.Drawing.Size(136, 17);\n            this.cb_ScreenBoundary.TabIndex = 2;\n            this.cb_ScreenBoundary.Text = \"Draw Screen Boundary\";\n            this.cb_ScreenBoundary.UseVisualStyleBackColor = true;\n            // \n            // cb_OverlayScreen\n            // \n            this.cb_OverlayScreen.AutoSize = true;\n            this.cb_OverlayScreen.Location = new System.Drawing.Point(12, 554);\n            this.cb_OverlayScreen.Name = \"cb_OverlayScreen\";\n            this.cb_OverlayScreen.Size = new System.Drawing.Size(99, 17);\n            this.cb_OverlayScreen.TabIndex = 3;\n            this.cb_OverlayScreen.Text = \"Overlay Screen\";\n            this.cb_OverlayScreen.UseVisualStyleBackColor = true;\n            // \n            // menuStrip1\n            // \n            this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {\n            this.fileToolStripMenuItem});\n            this.menuStrip1.Location = new System.Drawing.Point(0, 0);\n            this.menuStrip1.Name = \"menuStrip1\";\n            this.menuStrip1.Size = new System.Drawing.Size(512, 24);\n            this.menuStrip1.TabIndex = 4;\n            this.menuStrip1.Text = \"menuStrip1\";\n            // \n            // fileToolStripMenuItem\n            // \n            this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {\n            this.screenshotToolStripMenuItem});\n            this.fileToolStripMenuItem.Name = \"fileToolStripMenuItem\";\n            this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20);\n            this.fileToolStripMenuItem.Text = \"File\";\n            // \n            // screenshotToolStripMenuItem\n            // \n            this.screenshotToolStripMenuItem.Name = \"screenshotToolStripMenuItem\";\n            this.screenshotToolStripMenuItem.Size = new System.Drawing.Size(132, 22);\n            this.screenshotToolStripMenuItem.Text = \"Screenshot\";\n            this.screenshotToolStripMenuItem.Click += new System.EventHandler(this.screenshotToolStripMenuItem_Click);\n            // \n            // TriCNTViewer\n            // \n            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);\n            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;\n            this.ClientSize = new System.Drawing.Size(512, 579);\n            this.Controls.Add(this.cb_OverlayScreen);\n            this.Controls.Add(this.cb_ScreenBoundary);\n            this.Controls.Add(this.cb_ForcePal0ToBackdrop);\n            this.Controls.Add(this.pictureBox1);\n            this.Controls.Add(this.menuStrip1);\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;\n            this.Icon = ((System.Drawing.Icon)(resources.GetObject(\"$this.Icon\")));\n            this.MainMenuStrip = this.menuStrip1;\n            this.MaximizeBox = false;\n            this.MaximumSize = new System.Drawing.Size(528, 618);\n            this.MinimizeBox = false;\n            this.MinimumSize = new System.Drawing.Size(528, 618);\n            this.Name = \"TriCNTViewer\";\n            this.Text = \"Nametable Viewer\";\n            ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();\n            this.menuStrip1.ResumeLayout(false);\n            this.menuStrip1.PerformLayout();\n            this.ResumeLayout(false);\n            this.PerformLayout();\n\n        }\n\n        #endregion\n\n        private System.Windows.Forms.PictureBox pictureBox1;\n        private System.Windows.Forms.CheckBox cb_ForcePal0ToBackdrop;\n        private System.Windows.Forms.CheckBox cb_ScreenBoundary;\n        private System.Windows.Forms.CheckBox cb_OverlayScreen;\n        private System.Windows.Forms.MenuStrip menuStrip1;\n        private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem screenshotToolStripMenuItem;\n    }\n}"
  },
  {
    "path": "forms/TriCNTViewer.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Data;\nusing System.Drawing;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.Windows.Forms;\n\nnamespace TriCNES\n{\n    public partial class TriCNTViewer : Form\n    {\n        public TriCNESGUI MainGUI;\n        public TriCNTViewer()\n        {\n            InitializeComponent();\n            FormClosing += new FormClosingEventHandler(TriCNTViewer_Closing);\n        }\n\n        private void TriCNTViewer_Closing(Object sender, FormClosingEventArgs e)\n        {\n            MainGUI.NametableViewer = null;\n            this.Dispose();\n        }\n\n        public void Update(Bitmap b)\n        {\n            MethodInvoker upd = delegate\n            {\n                pictureBox1.Image = b;\n                pictureBox1.Update();\n            };\n            try\n            {\n                this.Invoke(upd);\n            }\n            catch (Exception e)\n            {\n\n            }\n        }\n\n        public bool UseBackdrop()\n        {\n            return cb_ForcePal0ToBackdrop.Checked;\n        }\n\n        public bool DrawBoundary()\n        {\n            return cb_ScreenBoundary.Checked;\n        }\n        public bool OverlayScreen()\n        {\n            return cb_OverlayScreen.Checked;\n        }\n\n        private void screenshotToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            Clipboard.SetImage(pictureBox1.Image);\n        }\n    }\n}\n"
  },
  {
    "path": "forms/TriCNTViewer.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <metadata name=\"menuStrip1.TrayLocation\" type=\"System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n    <value>17, 17</value>\n  </metadata>\n  <assembly alias=\"System.Drawing\" name=\"System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\" />\n  <data name=\"$this.Icon\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAA/wAA\n        AP8AAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAA\n        AP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA\n        AAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAA\n        AP8AAAD/AAAA/wAAAP8AAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAAAAAA\n        AAD///////////////////////////////8AAAAAAAAAAAAAAP8AAAD/AAAAAAAAAAD/////////////\n        //////////////////8AAAAAAAAAAAAAAP8AAAD/////////////////////////////////AAAAAAAA\n        AAAAAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//\n        /////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAA\n        AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////\n        ////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA////////\n        //8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAA\n        AP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAA\n        AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//\n        ////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAA\n        AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAA\n        AAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA////////\n        //8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA\n        AAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA\n        AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAA\n        AP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAA\n        AAAAAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//\n        ////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAA\n        AP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA\n        AAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/////////\n        //8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD//////////////////////wAA\n        AP8AAAD/AAAAAAAAAAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAA\n        AAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAAAAD/////////////\n        ////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/////////\n        //8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD///////////8AAAAAAAAAAAAA\n        AAAAAAAA//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////\n        //8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////////8AAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////////\n        /////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////////////////////////wAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAA///////////////////////////////////////////A8D8DwPA/AwPA\n        zAwDwMwMww8A8MMPAPDDDwDwww8A8MMPAPDDDwDwww8A8MMPAPADMDMDAzAzA8/A/A/PwPwP////////\n        //////////////////////////////////8=\n</value>\n  </data>\n</root>"
  },
  {
    "path": "forms/TriCTASTimeline.Designer.cs",
    "content": "﻿using System.Windows.Forms;\n\nnamespace TriCNES\n{\n    partial class TriCTASTimeline\n    {\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private System.ComponentModel.IContainer components = null;\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        /// <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing && (components != null))\n            {\n                components.Dispose();\n            }\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            this.components = new System.ComponentModel.Container();\n            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TriCTASTimeline));\n            this.pb_Timeline = new System.Windows.Forms.PictureBox();\n            this.timelineScrollbar = new System.Windows.Forms.VScrollBar();\n            this.b_FrameAdvance = new System.Windows.Forms.Button();\n            this.b_FrameBack = new System.Windows.Forms.Button();\n            this.menuStrip1 = new System.Windows.Forms.MenuStrip();\n            this.tASToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.loadTASToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.saveTASToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.saveWithSavestatesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.exportTor08ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.cellFrequencyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.perVBlankToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.perControllerStrobeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.b_play = new System.Windows.Forms.Button();\n            this.contextMenuStrip_Timeline = new System.Windows.Forms.ContextMenuStrip(this.components);\n            this.deleteFrameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.insertFrameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.truncateMovieToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.savestateThisFrameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();\n            this.b_JumptoCursor = new System.Windows.Forms.Button();\n            this.cb_FollowCursor = new System.Windows.Forms.CheckBox();\n            this.tb_FollowDistance = new System.Windows.Forms.TrackBar();\n            this.cb_SavestateEveryFrame = new System.Windows.Forms.CheckBox();\n            this.tb_TempSavestates = new System.Windows.Forms.TextBox();\n            this.label_TempSavestates = new System.Windows.Forms.Label();\n            this.Tooltip_ = new System.Windows.Forms.ToolTip(this.components);\n            this.label_AutoSavestateThreshold = new System.Windows.Forms.Label();\n            this.tb_AutoSavestateThreshold = new System.Windows.Forms.TextBox();\n            this.cb_RecordInputs = new System.Windows.Forms.CheckBox();\n            this.cb_player2 = new System.Windows.Forms.CheckBox();\n            ((System.ComponentModel.ISupportInitialize)(this.pb_Timeline)).BeginInit();\n            this.menuStrip1.SuspendLayout();\n            this.contextMenuStrip_Timeline.SuspendLayout();\n            ((System.ComponentModel.ISupportInitialize)(this.tb_FollowDistance)).BeginInit();\n            this.SuspendLayout();\n            // \n            // pb_Timeline\n            // \n            this.pb_Timeline.Location = new System.Drawing.Point(12, 27);\n            this.pb_Timeline.Name = \"pb_Timeline\";\n            this.pb_Timeline.Size = new System.Drawing.Size(353, 657);\n            this.pb_Timeline.TabIndex = 7;\n            this.pb_Timeline.TabStop = false;\n            // \n            // timelineScrollbar\n            // \n            this.timelineScrollbar.Location = new System.Drawing.Point(372, 27);\n            this.timelineScrollbar.Name = \"timelineScrollbar\";\n            this.timelineScrollbar.Size = new System.Drawing.Size(19, 657);\n            this.timelineScrollbar.TabIndex = 2;\n            // \n            // b_FrameAdvance\n            // \n            this.b_FrameAdvance.Location = new System.Drawing.Point(601, 38);\n            this.b_FrameAdvance.Name = \"b_FrameAdvance\";\n            this.b_FrameAdvance.Size = new System.Drawing.Size(75, 23);\n            this.b_FrameAdvance.TabIndex = 1;\n            this.b_FrameAdvance.Text = \">\";\n            this.b_FrameAdvance.UseVisualStyleBackColor = true;\n            this.b_FrameAdvance.Click += new System.EventHandler(this.b_FrameAdvance_Click);\n            // \n            // b_FrameBack\n            // \n            this.b_FrameBack.Location = new System.Drawing.Point(439, 38);\n            this.b_FrameBack.Name = \"b_FrameBack\";\n            this.b_FrameBack.Size = new System.Drawing.Size(75, 23);\n            this.b_FrameBack.TabIndex = 2;\n            this.b_FrameBack.Text = \"<\";\n            this.b_FrameBack.UseVisualStyleBackColor = true;\n            this.b_FrameBack.Click += new System.EventHandler(this.b_FrameBack_Click);\n            // \n            // menuStrip1\n            // \n            this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {\n            this.tASToolStripMenuItem,\n            this.settingsToolStripMenuItem});\n            this.menuStrip1.Location = new System.Drawing.Point(0, 0);\n            this.menuStrip1.Name = \"menuStrip1\";\n            this.menuStrip1.Size = new System.Drawing.Size(745, 24);\n            this.menuStrip1.TabIndex = 3;\n            this.menuStrip1.Text = \"menuStrip1\";\n            // \n            // tASToolStripMenuItem\n            // \n            this.tASToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {\n            this.loadTASToolStripMenuItem,\n            this.saveTASToolStripMenuItem,\n            this.saveWithSavestatesToolStripMenuItem,\n            this.exportTor08ToolStripMenuItem});\n            this.tASToolStripMenuItem.Name = \"tASToolStripMenuItem\";\n            this.tASToolStripMenuItem.Size = new System.Drawing.Size(37, 20);\n            this.tASToolStripMenuItem.Text = \"File\";\n            // \n            // loadTASToolStripMenuItem\n            // \n            this.loadTASToolStripMenuItem.Name = \"loadTASToolStripMenuItem\";\n            this.loadTASToolStripMenuItem.Size = new System.Drawing.Size(180, 22);\n            this.loadTASToolStripMenuItem.Text = \"Load\";\n            this.loadTASToolStripMenuItem.Click += new System.EventHandler(this.loadTASToolStripMenuItem_Click);\n            // \n            // saveTASToolStripMenuItem\n            // \n            this.saveTASToolStripMenuItem.Name = \"saveTASToolStripMenuItem\";\n            this.saveTASToolStripMenuItem.Size = new System.Drawing.Size(180, 22);\n            this.saveTASToolStripMenuItem.Text = \"Save\";\n            this.saveTASToolStripMenuItem.Click += new System.EventHandler(this.saveTASToolStripMenuItem_Click);\n            // \n            // saveWithSavestatesToolStripMenuItem\n            // \n            this.saveWithSavestatesToolStripMenuItem.Name = \"saveWithSavestatesToolStripMenuItem\";\n            this.saveWithSavestatesToolStripMenuItem.Size = new System.Drawing.Size(180, 22);\n            this.saveWithSavestatesToolStripMenuItem.Text = \"Save with savestates\";\n            this.saveWithSavestatesToolStripMenuItem.Click += new System.EventHandler(this.saveWithSavestatesToolStripMenuItem_Click);\n            // \n            // exportTor08ToolStripMenuItem\n            // \n            this.exportTor08ToolStripMenuItem.Name = \"exportTor08ToolStripMenuItem\";\n            this.exportTor08ToolStripMenuItem.Size = new System.Drawing.Size(180, 22);\n            this.exportTor08ToolStripMenuItem.Text = \"Export to .r08\";\n            this.exportTor08ToolStripMenuItem.Click += new System.EventHandler(this.exportTor08ToolStripMenuItem_Click);\n            // \n            // settingsToolStripMenuItem\n            // \n            this.settingsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {\n            this.cellFrequencyToolStripMenuItem});\n            this.settingsToolStripMenuItem.Name = \"settingsToolStripMenuItem\";\n            this.settingsToolStripMenuItem.Size = new System.Drawing.Size(61, 20);\n            this.settingsToolStripMenuItem.Text = \"Settings\";\n            // \n            // cellFrequencyToolStripMenuItem\n            // \n            this.cellFrequencyToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {\n            this.perVBlankToolStripMenuItem,\n            this.perControllerStrobeToolStripMenuItem});\n            this.cellFrequencyToolStripMenuItem.Name = \"cellFrequencyToolStripMenuItem\";\n            this.cellFrequencyToolStripMenuItem.Size = new System.Drawing.Size(152, 22);\n            this.cellFrequencyToolStripMenuItem.Text = \"Cell Frequency\";\n            // \n            // perVBlankToolStripMenuItem\n            // \n            this.perVBlankToolStripMenuItem.Checked = true;\n            this.perVBlankToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;\n            this.perVBlankToolStripMenuItem.Name = \"perVBlankToolStripMenuItem\";\n            this.perVBlankToolStripMenuItem.Size = new System.Drawing.Size(184, 22);\n            this.perVBlankToolStripMenuItem.Text = \"Per VBlank\";\n            this.perVBlankToolStripMenuItem.Click += new System.EventHandler(this.perVBlankToolStripMenuItem_Click);\n            // \n            // perControllerStrobeToolStripMenuItem\n            // \n            this.perControllerStrobeToolStripMenuItem.Name = \"perControllerStrobeToolStripMenuItem\";\n            this.perControllerStrobeToolStripMenuItem.Size = new System.Drawing.Size(184, 22);\n            this.perControllerStrobeToolStripMenuItem.Text = \"Per Controller Strobe\";\n            this.perControllerStrobeToolStripMenuItem.Click += new System.EventHandler(this.perControllerStrobeToolStripMenuItem_Click);\n            // \n            // b_play\n            // \n            this.b_play.Location = new System.Drawing.Point(521, 38);\n            this.b_play.Name = \"b_play\";\n            this.b_play.Size = new System.Drawing.Size(75, 23);\n            this.b_play.TabIndex = 4;\n            this.b_play.Text = \"Paused\";\n            this.b_play.UseVisualStyleBackColor = true;\n            this.b_play.Click += new System.EventHandler(this.b_play_Click);\n            // \n            // contextMenuStrip_Timeline\n            // \n            this.contextMenuStrip_Timeline.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {\n            this.deleteFrameToolStripMenuItem,\n            this.insertFrameToolStripMenuItem,\n            this.truncateMovieToolStripMenuItem,\n            this.savestateThisFrameToolStripMenuItem});\n            this.contextMenuStrip_Timeline.Name = \"contextMenuStrip_Timeline\";\n            this.contextMenuStrip_Timeline.Size = new System.Drawing.Size(184, 92);\n            // \n            // deleteFrameToolStripMenuItem\n            // \n            this.deleteFrameToolStripMenuItem.Name = \"deleteFrameToolStripMenuItem\";\n            this.deleteFrameToolStripMenuItem.Size = new System.Drawing.Size(183, 22);\n            this.deleteFrameToolStripMenuItem.Text = \"Delete Frame\";\n            this.deleteFrameToolStripMenuItem.Click += new System.EventHandler(this.deleteFrameToolStripMenuItem_Click);\n            // \n            // insertFrameToolStripMenuItem\n            // \n            this.insertFrameToolStripMenuItem.Name = \"insertFrameToolStripMenuItem\";\n            this.insertFrameToolStripMenuItem.Size = new System.Drawing.Size(183, 22);\n            this.insertFrameToolStripMenuItem.Text = \"Insert Frame\";\n            this.insertFrameToolStripMenuItem.Click += new System.EventHandler(this.insertFrameToolStripMenuItem_Click);\n            // \n            // truncateMovieToolStripMenuItem\n            // \n            this.truncateMovieToolStripMenuItem.Name = \"truncateMovieToolStripMenuItem\";\n            this.truncateMovieToolStripMenuItem.Size = new System.Drawing.Size(183, 22);\n            this.truncateMovieToolStripMenuItem.Text = \"Truncate Movie\";\n            this.truncateMovieToolStripMenuItem.Click += new System.EventHandler(this.truncateMovieToolStripMenuItem_Click);\n            // \n            // savestateThisFrameToolStripMenuItem\n            // \n            this.savestateThisFrameToolStripMenuItem.Name = \"savestateThisFrameToolStripMenuItem\";\n            this.savestateThisFrameToolStripMenuItem.Size = new System.Drawing.Size(183, 22);\n            this.savestateThisFrameToolStripMenuItem.Text = \"Savestate This Frame\";\n            this.savestateThisFrameToolStripMenuItem.Click += new System.EventHandler(this.savestateThisFrameToolStripMenuItem_Click);\n            // \n            // b_JumptoCursor\n            // \n            this.b_JumptoCursor.Location = new System.Drawing.Point(236, 699);\n            this.b_JumptoCursor.Name = \"b_JumptoCursor\";\n            this.b_JumptoCursor.Size = new System.Drawing.Size(99, 23);\n            this.b_JumptoCursor.TabIndex = 5;\n            this.b_JumptoCursor.Text = \"Jump to Cursor\";\n            this.b_JumptoCursor.UseVisualStyleBackColor = true;\n            this.b_JumptoCursor.Click += new System.EventHandler(this.b_JumptoCursor_Click);\n            // \n            // cb_FollowCursor\n            // \n            this.cb_FollowCursor.AutoSize = true;\n            this.cb_FollowCursor.Checked = true;\n            this.cb_FollowCursor.CheckState = System.Windows.Forms.CheckState.Checked;\n            this.cb_FollowCursor.Location = new System.Drawing.Point(26, 703);\n            this.cb_FollowCursor.Name = \"cb_FollowCursor\";\n            this.cb_FollowCursor.Size = new System.Drawing.Size(89, 17);\n            this.cb_FollowCursor.TabIndex = 6;\n            this.cb_FollowCursor.Text = \"Follow Cursor\";\n            this.cb_FollowCursor.UseVisualStyleBackColor = true;\n            // \n            // tb_FollowDistance\n            // \n            this.tb_FollowDistance.LargeChange = 1;\n            this.tb_FollowDistance.Location = new System.Drawing.Point(118, 699);\n            this.tb_FollowDistance.Maximum = 39;\n            this.tb_FollowDistance.Name = \"tb_FollowDistance\";\n            this.tb_FollowDistance.Size = new System.Drawing.Size(104, 45);\n            this.tb_FollowDistance.TabIndex = 8;\n            this.tb_FollowDistance.Value = 20;\n            this.tb_FollowDistance.Scroll += new System.EventHandler(this.tb_FollowDistance_Scroll);\n            // \n            // cb_SavestateEveryFrame\n            // \n            this.cb_SavestateEveryFrame.AutoSize = true;\n            this.cb_SavestateEveryFrame.Location = new System.Drawing.Point(409, 112);\n            this.cb_SavestateEveryFrame.Name = \"cb_SavestateEveryFrame\";\n            this.cb_SavestateEveryFrame.Size = new System.Drawing.Size(136, 17);\n            this.cb_SavestateEveryFrame.TabIndex = 9;\n            this.cb_SavestateEveryFrame.Text = \"Savestate Every Frame\";\n            this.cb_SavestateEveryFrame.UseVisualStyleBackColor = true;\n            // \n            // tb_TempSavestates\n            // \n            this.tb_TempSavestates.Location = new System.Drawing.Point(410, 132);\n            this.tb_TempSavestates.MaxLength = 5;\n            this.tb_TempSavestates.Name = \"tb_TempSavestates\";\n            this.tb_TempSavestates.Size = new System.Drawing.Size(41, 20);\n            this.tb_TempSavestates.TabIndex = 10;\n            this.tb_TempSavestates.Text = \"120\";\n            this.Tooltip_.SetToolTip(this.tb_TempSavestates, resources.GetString(\"tb_TempSavestates.ToolTip\"));\n            this.tb_TempSavestates.TextChanged += new System.EventHandler(this.tb_TempSavestates_TextChanged);\n            this.tb_TempSavestates.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.tb_FilterForNumbers);\n            // \n            // label_TempSavestates\n            // \n            this.label_TempSavestates.AutoSize = true;\n            this.label_TempSavestates.Location = new System.Drawing.Point(457, 139);\n            this.label_TempSavestates.Name = \"label_TempSavestates\";\n            this.label_TempSavestates.Size = new System.Drawing.Size(139, 13);\n            this.label_TempSavestates.TabIndex = 11;\n            this.label_TempSavestates.Text = \"Temporary Savestate Count\";\n            this.Tooltip_.SetToolTip(this.label_TempSavestates, resources.GetString(\"label_TempSavestates.ToolTip\"));\n            // \n            // Tooltip_\n            // \n            this.Tooltip_.AutoPopDelay = 500000;\n            this.Tooltip_.InitialDelay = 500;\n            this.Tooltip_.ReshowDelay = 100;\n            // \n            // label_AutoSavestateThreshold\n            // \n            this.label_AutoSavestateThreshold.AutoSize = true;\n            this.label_AutoSavestateThreshold.Location = new System.Drawing.Point(457, 165);\n            this.label_AutoSavestateThreshold.Name = \"label_AutoSavestateThreshold\";\n            this.label_AutoSavestateThreshold.Size = new System.Drawing.Size(130, 13);\n            this.label_AutoSavestateThreshold.TabIndex = 13;\n            this.label_AutoSavestateThreshold.Text = \"Auto-Savestate Threshold\";\n            this.Tooltip_.SetToolTip(this.label_AutoSavestateThreshold, \"Automatically make a savestate every \\'n\\' frames.\\r\\nA larger value will consume les\" +\n        \"s RAM, but leave gaps that will need to be re-emulated when loading earlier fram\" +\n        \"es.\\r\\n\");\n            // \n            // tb_AutoSavestateThreshold\n            // \n            this.tb_AutoSavestateThreshold.Location = new System.Drawing.Point(410, 158);\n            this.tb_AutoSavestateThreshold.MaxLength = 5;\n            this.tb_AutoSavestateThreshold.Name = \"tb_AutoSavestateThreshold\";\n            this.tb_AutoSavestateThreshold.Size = new System.Drawing.Size(41, 20);\n            this.tb_AutoSavestateThreshold.TabIndex = 12;\n            this.tb_AutoSavestateThreshold.Text = \"500\";\n            this.Tooltip_.SetToolTip(this.tb_AutoSavestateThreshold, \"Automatically make a savestate every \\'n\\' frames.\\r\\nA larger value will consume les\" +\n        \"s RAM, but leave gaps that will need to be re-emulated when loading earlier fram\" +\n        \"es.\");\n            this.tb_AutoSavestateThreshold.TextChanged += new System.EventHandler(this.tb_AutoSavestateThreshold_TextChanged);\n            this.tb_AutoSavestateThreshold.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.tb_FilterForNumbers);\n            // \n            // cb_RecordInputs\n            // \n            this.cb_RecordInputs.AutoSize = true;\n            this.cb_RecordInputs.Location = new System.Drawing.Point(409, 89);\n            this.cb_RecordInputs.Name = \"cb_RecordInputs\";\n            this.cb_RecordInputs.Size = new System.Drawing.Size(93, 17);\n            this.cb_RecordInputs.TabIndex = 14;\n            this.cb_RecordInputs.Text = \"Record Inputs\";\n            this.Tooltip_.SetToolTip(this.cb_RecordInputs, \"If checked, the inputs you provide will be recorded on the timeline.\\r\\nThis will o\" +\n        \"verwrite older frames if you rewind.\");\n            this.cb_RecordInputs.UseVisualStyleBackColor = true;\n            // \n            // cb_player2\n            // \n            this.cb_player2.AutoSize = true;\n            this.cb_player2.Location = new System.Drawing.Point(508, 89);\n            this.cb_player2.Name = \"cb_player2\";\n            this.cb_player2.Size = new System.Drawing.Size(64, 17);\n            this.cb_player2.TabIndex = 15;\n            this.cb_player2.Text = \"Player 2\";\n            this.Tooltip_.SetToolTip(this.cb_player2, \"If checked, the inputs you provide will be recorded on the timeline.\\r\\nThis will o\" +\n        \"verwrite older frames if you rewind.\");\n            this.cb_player2.UseVisualStyleBackColor = true;\n            // \n            // TriCTASTimeline\n            // \n            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);\n            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;\n            this.ClientSize = new System.Drawing.Size(745, 743);\n            this.Controls.Add(this.cb_player2);\n            this.Controls.Add(this.cb_RecordInputs);\n            this.Controls.Add(this.label_AutoSavestateThreshold);\n            this.Controls.Add(this.tb_AutoSavestateThreshold);\n            this.Controls.Add(this.label_TempSavestates);\n            this.Controls.Add(this.tb_TempSavestates);\n            this.Controls.Add(this.cb_SavestateEveryFrame);\n            this.Controls.Add(this.tb_FollowDistance);\n            this.Controls.Add(this.timelineScrollbar);\n            this.Controls.Add(this.pb_Timeline);\n            this.Controls.Add(this.cb_FollowCursor);\n            this.Controls.Add(this.b_JumptoCursor);\n            this.Controls.Add(this.b_play);\n            this.Controls.Add(this.menuStrip1);\n            this.Controls.Add(this.b_FrameBack);\n            this.Controls.Add(this.b_FrameAdvance);\n            this.Icon = ((System.Drawing.Icon)(resources.GetObject(\"$this.Icon\")));\n            this.Name = \"TriCTASTimeline\";\n            this.Text = \"TAS Timeline\";\n            ((System.ComponentModel.ISupportInitialize)(this.pb_Timeline)).EndInit();\n            this.menuStrip1.ResumeLayout(false);\n            this.menuStrip1.PerformLayout();\n            this.contextMenuStrip_Timeline.ResumeLayout(false);\n            ((System.ComponentModel.ISupportInitialize)(this.tb_FollowDistance)).EndInit();\n            this.ResumeLayout(false);\n            this.PerformLayout();\n\n        }\n\n        #endregion\n        private System.Windows.Forms.Button b_FrameAdvance;\n        private System.Windows.Forms.VScrollBar timelineScrollbar;\n        private System.Windows.Forms.Button b_FrameBack;\n        private System.Windows.Forms.MenuStrip menuStrip1;\n        private System.Windows.Forms.ToolStripMenuItem tASToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem loadTASToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem saveTASToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem settingsToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem exportTor08ToolStripMenuItem;\n        private System.Windows.Forms.Button b_play;\n        private System.Windows.Forms.ContextMenuStrip contextMenuStrip_Timeline;\n        private System.Windows.Forms.ToolStripMenuItem deleteFrameToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem insertFrameToolStripMenuItem;\n        private System.Windows.Forms.ToolStripMenuItem truncateMovieToolStripMenuItem;\n        private System.Windows.Forms.Button b_JumptoCursor;\n        private System.Windows.Forms.CheckBox cb_FollowCursor;\n        private System.Windows.Forms.PictureBox pb_Timeline;\n        private System.Windows.Forms.TrackBar tb_FollowDistance;\n        private System.Windows.Forms.ToolStripMenuItem savestateThisFrameToolStripMenuItem;\n        private System.Windows.Forms.CheckBox cb_SavestateEveryFrame;\n        private System.Windows.Forms.TextBox tb_TempSavestates;\n        private System.Windows.Forms.Label label_TempSavestates;\n        private System.Windows.Forms.ToolTip Tooltip_;\n        private System.Windows.Forms.Label label_AutoSavestateThreshold;\n        private System.Windows.Forms.TextBox tb_AutoSavestateThreshold;\n        private System.Windows.Forms.ToolStripMenuItem saveWithSavestatesToolStripMenuItem;\n        private CheckBox cb_RecordInputs;\n        private ToolStripMenuItem cellFrequencyToolStripMenuItem;\n        private ToolStripMenuItem perVBlankToolStripMenuItem;\n        private ToolStripMenuItem perControllerStrobeToolStripMenuItem;\n        private CheckBox cb_player2;\n    }\n}"
  },
  {
    "path": "forms/TriCTASTimeline.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Drawing;\nusing System.IO;\nusing System.Runtime.InteropServices;\nusing System.Security.Cryptography;\nusing System.Timers;\nusing System.Windows.Forms;\nusing static System.Windows.Forms.AxHost;\n\nnamespace TriCNES\n{\n    public partial class TriCTASTimeline : Form\n    {\n        public Font Font_Consolas;\n        public Brush Brush_LeftColumn;\n        public Brush Brush_LeftColumn_Saved;\n        public Brush Brush_LeftColumn_TempSaved;\n        public Brush Brush_HighlightedCell;\n        public Brush Brush_WhiteCellP1;\n        public Brush Brush_WhiteCellP2;\n        public Brush Brush_GreenCellP1;\n        public Brush Brush_GreenCellP2;\n        public Brush Brush_GreenCellP1_Stale;\n        public Brush Brush_GreenCellP2_Stale;\n        public Brush Brush_RedCellP1;\n        public Brush Brush_RedCellP2;\n        public Brush Brush_RedCellP1_Stale;\n        public Brush Brush_RedCellP2_Stale;\n\n        struct Vector2\n        {\n            public int x;\n            public int y;\n            public Vector2(int X, int Y)\n            {\n                x = X;\n                y = Y;\n            }\n            public override string ToString()\n            {\n                return x.ToString() + \", \" + y.ToString();\n            }\n        }\n\n        public struct TimelineCell\n        {\n            public bool Checked;\n            public bool LagFrame;\n            public bool Stale;\n            public bool Emulated;\n            public TimelineCell(bool t)\n            {\n                Checked = false;\n                LagFrame = false;\n                Stale = false;\n                Emulated = false;\n            }\n        }\n        public int SavestateLength;\n        public int Rerecords;\n        public TriCTASTimeline(TriCNESGUI Maingui)\n        {\n            MainGUI = Maingui;\n            InitializeComponent();\n\n            Font_Consolas = new Font(\"Consolas\", 8);\n            Brush_LeftColumn = new SolidBrush(Color.LightGray);\n            Brush_LeftColumn_Saved = new SolidBrush(Color.Wheat);\n            Brush_LeftColumn_TempSaved = new SolidBrush(Color.LemonChiffon);\n            Brush_HighlightedCell = new SolidBrush(Color.LightBlue);\n            Brush_WhiteCellP1 = new SolidBrush(Color.WhiteSmoke);\n            Brush_WhiteCellP2 = new SolidBrush(Color.FromArgb(255, 230, 230, 230));\n            Brush_GreenCellP1 = new SolidBrush(Color.FromArgb(255, 200, 240, 200));\n            Brush_GreenCellP2 = new SolidBrush(Color.FromArgb(255, 190, 232, 190));\n            Brush_GreenCellP1_Stale = new SolidBrush(Color.FromArgb(255, 205, 220, 205));\n            Brush_GreenCellP2_Stale = new SolidBrush(Color.FromArgb(255, 195, 215, 195));\n            Brush_RedCellP1 = new SolidBrush(Color.FromArgb(255, 240, 200, 200));\n            Brush_RedCellP2 = new SolidBrush(Color.FromArgb(255, 232, 190, 190));\n            Brush_RedCellP1_Stale = new SolidBrush(Color.FromArgb(255, 220, 205, 205));\n            Brush_RedCellP2_Stale = new SolidBrush(Color.FromArgb(255, 215, 195, 195));\n            Inputs = new List<ushort>();\n\n            Start();\n            Inputs.Add(0);\n            Resets.Add(false);\n\n            timelineBitmap = new Bitmap(80 + 16 * 17 + 1, 41 * 16 + 1);\n            G = Graphics.FromImage(timelineBitmap);\n            pb_Timeline.Image = timelineBitmap;\n            pb_Timeline.MouseDown += mouseDownEvent;\n            pb_Timeline.MouseUp += mouseUpEvent;\n            pb_Timeline.ContextMenuStrip = contextMenuStrip_Timeline;\n            pb_Timeline.MouseWheel += mouseWheelEvent;\n            timelineScrollbar.ValueChanged += timelineScrollbar_ValueChanged;\n\n            //loop timer\n            loopTimer = new System.Timers.Timer();\n            loopTimer.Interval = 50;// interval in milliseconds\n            loopTimer.Enabled = false;\n            loopTimer.Elapsed += loopTimerEvent;\n            loopTimer.AutoReset = true;\n\n            autosave = new System.Timers.Timer();\n            autosave.Interval = 60000;\n            autosave.Elapsed += autosaveEvent;\n            autosave.AutoReset = true;\n            autosave.Enabled = true;\n\n\n            Shown += TriCTASTimeline_Shown;\n        }\n\n        private void mouseWheelEvent(object sender, MouseEventArgs e)\n        {\n            int result = timelineScrollbar.Value - Math.Sign(e.Delta);\n            if (result > timelineScrollbar.Maximum - timelineScrollbar.LargeChange + 1)\n            {\n                result = timelineScrollbar.Maximum - timelineScrollbar.LargeChange + 1;\n            }\n            else if (result < 0)\n            {\n                result = 0;\n            }\n            timelineScrollbar.Value = result;\n        }\n\n        void TriCTASTimeline_Shown(object sender, EventArgs e)\n        {\n            RefreshTopOfTimeline();\n        }\n\n        void RefreshTopOfTimeline()\n        {\n            Rectangle[] GridOverlay = new Rectangle[]\n                {\n                new Rectangle(0,0,80,16),\n                new Rectangle(80 + 16*0,0,16,16),\n                new Rectangle(80 + 16*1,0,16,16),\n                new Rectangle(80 + 16*2,0,16,16),\n                new Rectangle(80 + 16*3,0,16,16),\n                new Rectangle(80 + 16*4,0,16,16),\n                new Rectangle(80 + 16*5,0,16,16),\n                new Rectangle(80 + 16*6,0,16,16),\n                new Rectangle(80 + 16*7,0,16,16),\n                new Rectangle(80 + 16*8,0,16,16),\n                new Rectangle(80 + 16*9,0,16,16),\n                new Rectangle(80 + 16*10,0,16,16),\n                new Rectangle(80 + 16*11,0,16,16),\n                new Rectangle(80 + 16*12,0,16,16),\n                new Rectangle(80 + 16*13,0,16,16),\n                new Rectangle(80 + 16*14,0,16,16),\n                new Rectangle(80 + 16*15,0,16,16),\n                new Rectangle(80 + 16*16,0,16,16)\n                };\n            G.FillRectangle(Brush_LeftColumn, new Rectangle(0, 0, 80 + 16 * 17, 16));\n            G.DrawRectangles(Pens.Black, GridOverlay);\n            G.DrawString(ClockFiltering ? \"Input #\" : \"Frame #\", Font_Consolas, Brushes.Black, 0, 0);\n            G.DrawString(\"A\", Font_Consolas, Brushes.Black, 80 + 16 * 0, 0);\n            G.DrawString(\"B\", Font_Consolas, Brushes.Black, 80 + 16 * 1, 0);\n            G.DrawString(\"s\", Font_Consolas, Brushes.Black, 80 + 16 * 2, 0);\n            G.DrawString(\"S\", Font_Consolas, Brushes.Black, 80 + 16 * 3, 0);\n            G.DrawString(\"U\", Font_Consolas, Brushes.Black, 80 + 16 * 4, 0);\n            G.DrawString(\"D\", Font_Consolas, Brushes.Black, 80 + 16 * 5, 0);\n            G.DrawString(\"L\", Font_Consolas, Brushes.Black, 80 + 16 * 6, 0);\n            G.DrawString(\"R\", Font_Consolas, Brushes.Black, 80 + 16 * 7, 0);\n            G.DrawString(\"A\", Font_Consolas, Brushes.Black, 80 + 16 * 8, 0);\n            G.DrawString(\"B\", Font_Consolas, Brushes.Black, 80 + 16 * 9, 0);\n            G.DrawString(\"s\", Font_Consolas, Brushes.Black, 80 + 16 * 10, 0);\n            G.DrawString(\"S\", Font_Consolas, Brushes.Black, 80 + 16 * 11, 0);\n            G.DrawString(\"U\", Font_Consolas, Brushes.Black, 80 + 16 * 12, 0);\n            G.DrawString(\"D\", Font_Consolas, Brushes.Black, 80 + 16 * 13, 0);\n            G.DrawString(\"L\", Font_Consolas, Brushes.Black, 80 + 16 * 14, 0);\n            G.DrawString(\"R\", Font_Consolas, Brushes.Black, 80 + 16 * 15, 0);\n            G.DrawString(\"r\", Font_Consolas, Brushes.Black, 80 + 16 * 16, 0);\n            RefreshTimeline();\n        }\n\n        public Graphics G;\n        public Bitmap timelineBitmap;\n\n        private static System.Timers.Timer loopTimer;\n\n        private static System.Timers.Timer autosave;\n\n        private void loopTimerEvent(Object source, ElapsedEventArgs e)\n        {\n            //this does whatever you want to happen while clicking on the button\n            MainGUI.Timeline_PendingMouseHeld = true;\n        }\n\n        private void autosaveEvent(Object source, ElapsedEventArgs e)\n        {\n            if (Inputs.Count > 1000)\n            {\n                string InitDirectory = AppDomain.CurrentDomain.BaseDirectory;\n                if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @\"tas\\\"))\n                {\n                    InitDirectory += @\"tas\\\";\n                }\n                InitDirectory += \"autosave.3c2\";\n                FileStream fs = File.OpenWrite(InitDirectory);\n                for (int i = 0; i < Inputs.Count; i++)\n                {\n                    fs.WriteByte((byte)Inputs[i]);\n                    fs.WriteByte((byte)(Inputs[i] >> 8));\n                }\n                fs.Close();\n            }\n\n        }\n\n        public void TimelineMouseHeldEvent()\n        {\n            MethodInvoker upd = delegate\n            {\n                int mouseX = MousePosition.X - Left - pb_Timeline.Left - 8;\n                int mouseY = MousePosition.Y - Top - pb_Timeline.Top - 48;\n\n                int Column = mouseX >= 80 ? (mouseX - 80) / 16 : -1;\n                if (Column > 15) { Column = 15; }\n\n                int Row = mouseY >= 0 ? mouseY / 16 : -1;\n                if (Row > 39) { Row = 39; }\n\n                Vector2 mousePos = new Vector2(Column, Row);\n\n                if (mouseHeld_initPos.y >= 0)\n                {\n                    if (mouseHeld_initPos.x >= 0)\n                    {\n                        // we clicked on a cell\n                        int spos = Math.Min(mousePos.y, mouseHeld_initPos.y);\n                        int tpos = Math.Max(mousePos.y, mouseHeld_initPos.y);\n                        if (spos < 0)\n                        {\n                            spos = 0;\n                        }\n\n                        for (int i = spos; i <= tpos; i++)\n                        {\n                            if (mouseHeld_initPos.x == 16)\n                            {\n                                TimelineGrid[i][17].Checked = mouseHeld_setInput;\n                                RedrawTimelineRow(i, false);\n                                int frame = i + TopFrame;\n                                while (frame >= Inputs.Count)\n                                {\n                                    Inputs.Add(0);\n                                    Resets.Add(false);\n                                }\n                                if (Inputs.Count + 39 > timelineScrollbar.Maximum)\n                                {\n                                    timelineScrollbar.Maximum = Inputs.Count + 38;\n                                }\n                                Resets[frame] = mouseHeld_setInput;\n                            }\n                            else\n                            {\n                                bool state = GetCellInputStatus(new Vector2(mouseHeld_initPos.x, i));\n                                if (state != mouseHeld_setInput)\n                                {\n                                    ushort input = SetCellInputStatus(new Vector2(mouseHeld_initPos.x, i), mouseHeld_setInput);\n                                    TimelineGrid[i][mouseHeld_initPos.x + 1].Checked = mouseHeld_setInput;\n\n                                    RecalculateTimelineRow(i, input);\n                                    RedrawTimelineRow(i, false);\n                                }\n                            }\n                        }\n                        int checkStale = spos + TopFrame;\n                        if (checkStale < frameEmulated)\n                        {\n                            MarkStale(checkStale);\n                        }\n                    }\n                    else\n                    {\n                        // we clicked on the frame number.\n\n                    }\n                }\n\n\n\n            };\n            this.Invoke(upd);\n        }\n\n        public int TopFrame = 0;\n\n        Vector2 mouseHeld_initPos;\n        bool mouseHeld_setInput;\n        private void mouseDownEvent(object sender, MouseEventArgs e)\n        {\n            if (e.Button == MouseButtons.Right)\n            {\n                return;\n            }\n            loopTimer.Enabled = true;\n            int mouseX = MousePosition.X - Left - pb_Timeline.Left - 8;\n            int mouseY = MousePosition.Y - Top - pb_Timeline.Top - 48;\n\n            int Column = mouseX >= 80 ? (mouseX - 80) / 16 : -1;\n            if (Column > 16) { Column = 16; }\n\n            int Row = mouseY >= 0 ? mouseY / 16 : -1;\n            if (Row > 39) { Row = 39; }\n\n            mouseHeld_initPos = new Vector2(Column, Row);\n\n            MainGUI.Timeline_PendingMouseDown = true;\n\n        }\n\n        public void TimelineMouseDownEvent()\n        {\n            MethodInvoker upd = delegate\n            {\n                if (mouseHeld_initPos.y >= 0)\n                {\n                    if (mouseHeld_initPos.x >= 0)\n                    {\n                        // we clicked on a cell\n                        mouseHeld_setInput = !GetCellInputStatus(mouseHeld_initPos);\n                        int frameClicked = TopFrame + mouseHeld_initPos.y;\n\n                        if (mouseHeld_initPos.x == 16)\n                        {\n                            TimelineGrid[mouseHeld_initPos.y][17].Checked = mouseHeld_setInput;\n                            RedrawTimelineRow(mouseHeld_initPos.y, false);\n                            while (frameClicked >= Inputs.Count)\n                            {\n                                Inputs.Add(0);\n                                Resets.Add(false);\n                            }\n                            if (Inputs.Count + 39 > timelineScrollbar.Maximum)\n                            {\n                                timelineScrollbar.Maximum = Inputs.Count + 38;\n                            }\n                            Resets[frameClicked] = mouseHeld_setInput;\n                        }\n                        else\n                        {\n                            // calculate if that cell had an input or not.\n                            ushort input = SetCellInputStatus(mouseHeld_initPos, mouseHeld_setInput);\n                            TimelineGrid[mouseHeld_initPos.y][mouseHeld_initPos.x + 1].Checked = mouseHeld_setInput;\n\n                            RecalculateTimelineRow(mouseHeld_initPos.y, input);\n                            RedrawTimelineRow(mouseHeld_initPos.y, false);\n                        }\n                        if (frameClicked < frameEmulated)\n                        {\n                            MarkStale(frameClicked);\n                        }\n                    }\n                    else\n                    {\n                        // we clicked on the frame number.\n                        // TODO: Move the cursor to this frame.\n                        // - If there exists a savestate for this frame, then simply laod it.\n                        // - Otherwise, we haven't seen this frame yet. Load the last savestate in the list, then emulate to this frame.\n                        int frameClicked = TopFrame + mouseHeld_initPos.y;\n                        if (frameClicked == frameIndex)\n                        {\n                            return; // we're already on that frame!\n                        }\n                        if (frameClicked < frameEmulated && (TimelineSavestates[frameClicked].Count == SavestateLength || TimelineTempSavestates[frameClicked].Count == SavestateLength))\n                        {\n                            int prevrow = frameIndex - TopFrame;\n                            frameIndex = frameClicked - 1; // and we're good to go.\n                            if (frameIndex == -1)\n                            {\n                                frameIndex = 0;\n                                MainGUI.Timeline_LoadState = TimelineSavestates[0];\n                                MainGUI.Timeline_PendingLoadState = true;\n                                MainGUI.Timeline_PendingFrameNumber = 0;\n                                UpdateTimelineRowStatus(prevrow);\n                                RedrawTimelineRow(prevrow, false);\n                                UpdateTimelineRowStatus(0);\n                                RedrawTimelineRow(0, false);\n                                MainGUI.Timeline_PendingResetScreen = true;\n                            }\n                            else\n                            {\n                                MainGUI.Timeline_LoadState = GrabMostRecentSavestate(); // This function updates frameIndex\n                                MainGUI.Timeline_PendingLoadState = true;\n                                MainGUI.Timeline_PendingFrameNumber = frameIndex;\n                                MainGUI.Timeline_PendingFrameAdvance = true;\n\n                                UpdateTimelineRowStatus(prevrow);\n                                RedrawTimelineRow(prevrow, false);\n                            }\n\n\n                        }\n                        else\n                        {\n                            int row = frameIndex - TopFrame;\n                            int prevFrame = frameIndex;\n                            frameIndex = frameClicked;\n                            if (frameIndex > frameEmulated)\n                            {\n                                frameIndex = frameEmulated;\n                            }\n                            UpdateTimelineRowStatus(row);\n                            RedrawTimelineRow(row, false);\n                            if (frameIndex < 0)\n                            {\n                                frameIndex = 0;\n                            }\n                            else\n                            {\n                                bool Unneeded = false;\n                                MainGUI.Timeline_LoadState = GrabMostRecentSavestate(prevFrame, out Unneeded); // This function updates frameIndex\n                                if (!Unneeded)\n                                {\n                                    MainGUI.Timeline_PendingLoadState = true;\n                                    MainGUI.Timeline_PendingFrameNumber = frameIndex;\n                                }\n                            }\n                            // Now we need to emulate all the way until we reach the target frame.\n                            MainGUI.Timeline_AutoPlayUntilTarget = true;\n                            MainGUI.Timeline_AutoPlayTarget = frameClicked;\n                            row = frameIndex - TopFrame;\n\n                            UpdateTimelineRowStatus(row);\n                            RedrawTimelineRow(row, false);\n\n                            if (frameIndex > frameEmulated)\n                            {\n                                frameEmulated = frameIndex;\n                            }\n                            if (frameIndex > highestFrameEmulatedEver)\n                            {\n                                highestFrameEmulatedEver = frameIndex;\n                            }\n                            while (frameIndex >= Inputs.Count)\n                            {\n                                Inputs.Add(0);\n                                Resets.Add(false);\n                            }\n                            if (Inputs.Count + 39 > timelineScrollbar.Maximum)\n                            {\n                                timelineScrollbar.Maximum = Inputs.Count + 38;\n                            }\n                        }\n\n                    }\n                }\n            };\n            this.Invoke(upd); // Use delegates here because this could otherwise modify the state of the timeline mid-rendering the timeline. (causing runtime errors)\n        }\n\n        public void MarkStale(int Frame)\n        {\n            frameEmulated = Frame; // mark everything after this as \"stale\"\n            if (frameIndex >= Frame)\n            {\n                Rerecords++;\n                frameIndex = Frame;\n                TimelineSavestates.RemoveRange(frameIndex + 1, TimelineSavestates.Count - (frameIndex + 1));\n                TimelineTempSavestates.RemoveRange(frameIndex + 1, TimelineTempSavestates.Count - (frameIndex + 1));\n                //TEMPRerecordTracker.RemoveRange(frameIndex + 1, TEMPRerecordTracker.Count - (frameIndex + 1));\n                MainGUI.Timeline_LoadState = GrabMostRecentSavestate(); // This function updates frameIndex\n                System.GC.Collect();\n                MainGUI.Timeline_PendingLoadState = true;\n                MainGUI.Timeline_PendingFrameNumber = frameIndex;\n            }\n            RefreshTimeline();\n        }\n        private void mouseUpEvent(object sender, MouseEventArgs e)\n        {\n            if (e.Button == MouseButtons.Right)\n            {\n                return;\n            }\n            loopTimer.Enabled = false;\n        }\n\n        bool GetCellInputStatus(Vector2 pos)\n        {\n            if (pos.x < 0 || pos.y < 0)\n            {\n                return false; // should never happen\n            }\n            int frame = pos.y + TopFrame;\n            // get frame index\n            if (frame >= Inputs.Count)\n            {\n                return false;\n            }\n            if (pos.x == 16)\n            {\n                return Resets[frame];\n            }\n            int shift = (7 - (pos.x & 7)) | (pos.x & 8);\n            return ((Inputs[frame] >> shift) & 1) == 1;\n        }\n        ushort SetCellInputStatus(Vector2 pos, bool state)\n        {\n            if (pos.x < 0 || pos.y < 0)\n            {\n                return 0; // should never happen\n            }\n            // get frame index\n            int frame = pos.y + TopFrame;\n            int shift = (7 - (pos.x & 7)) | (pos.x & 8);\n            int prevInputs = Inputs.Count;\n            while (frame >= Inputs.Count)\n            {\n                // Add new inputs until you reach this frame\n                if (state)\n                {\n                    //Inputs.Add((ushort)(1 << shift));\n                    Inputs.Add(0);\n                    Resets.Add(false);\n                }\n                else\n                {\n                    Inputs.Add(0);\n                    Resets.Add(false);\n                }\n            }\n            if ((Inputs.Count > prevInputs))\n            {\n                timelineScrollbar.Maximum = Inputs.Count + 38;\n            }\n            if (state)\n            {\n                Inputs[frame] |= (ushort)(1 << shift);\n            }\n            else\n            {\n                Inputs[frame] &= (ushort)(0xFFFF ^ (1 << shift));\n            }\n            return Inputs[frame];\n        }\n\n        public TriCNESGUI MainGUI;\n\n        public static List<bool> LagFrames;\n        public static List<TimelineCell[]> TimelineGrid;\n        public static List<List<byte>> TimelineSavestates;\n        public static List<List<byte>> TimelineTempSavestates;\n        public static List<int> TEMPRerecordTracker;\n        public static List<bool> Resets;\n\n        public static List<ushort> Inputs; // high byte = controller 2\n\n        public int frameIndex;\n        public int highestFrameEmulatedEver; // highest emulated frame\n        public int frameEmulated; // highest emulated frame for the purposes of tracking stale frames\n\n        int AutoSavestateThreshold = 500;\n        int TempSavestates = 120;\n\n        public void Start()\n        {\n            TimelineGrid = new List<TimelineCell[]>();\n            TimelineSavestates = new List<List<byte>>();\n            TimelineTempSavestates = new List<List<byte>>();\n            LagFrames = new List<bool>();\n            Resets = new List<bool>();\n            //TEMPRerecordTracker = new List<int>();\n\n\n            for (int i = 0; i < 40; i++)\n            {\n                TimelineCell[] t = new TimelineCell[18];\n                for (int j = 0; j < t.Length; j++)\n                {\n                    t[0] = new TimelineCell(false);\n                }\n                TimelineGrid.Add(t);\n            }\n\n            Rerecords = 0;\n            frameIndex = 0;\n\n            timelineScrollbar.Maximum = Inputs.Count + 38;\n            timelineScrollbar.LargeChange = 40;\n\n            MainGUI.CreateTASTimelineEmulator();\n\n            List<byte> state = MainGUI.EMU.SaveState();\n            TimelineSavestates.Add(state);\n            TimelineTempSavestates.Add(new List<byte>());\n            SavestateLength = state.Count;\n            //TEMPRerecordTracker.Add(Rerecords);\n        }\n\n\n        int ScrollbarValue = 0;\n        private void timelineScrollbar_ValueChanged(object sender, EventArgs e)\n        {\n            TopFrame = timelineScrollbar.Value;\n            if (TopFrame != ScrollbarValue)\n            {\n                ScrollbarValue = TopFrame;\n                RefreshTimeline();\n            }\n        }\n\n        private void b_FrameAdvance_Click(object sender, EventArgs e)\n        {\n            MainGUI.Timeline_PendingFrameAdvance = true;\n        }\n\n        private void b_FrameBack_Click(object sender, EventArgs e)\n        {\n            FrameRewind();\n        }\n\n        public void FrameRewind()\n        {\n            int row = frameIndex - TopFrame;\n            int rowm1 = row - 1;\n            frameIndex -= 2;\n            if (frameIndex < 0)\n            {\n                frameIndex = 0;\n            }\n\n            UpdateTimelineRowStatus(row);\n            RedrawTimelineRow(row, false);\n\n            MainGUI.Timeline_LoadState = GrabMostRecentSavestate(); // This function updates frameIndex\n            MainGUI.Timeline_PendingLoadState = true;\n            MainGUI.Timeline_PendingFrameNumber = frameIndex;\n            if (frameIndex == 0)\n            {\n                UpdateTimelineRowStatus(0);\n                RedrawTimelineRow(0, false);\n                MainGUI.Timeline_PendingResetScreen = true;\n            }\n            else\n            {\n                MainGUI.Timeline_PendingFrameNumber = frameIndex;\n                MainGUI.Timeline_PendingFrameAdvance = true;\n            }\n            if (frameIndex != rowm1)\n            {\n                MainGUI.Timeline_AutoPlayUntilTarget = true;\n                MainGUI.Timeline_AutoPlayTarget = rowm1;\n            }\n        }\n\n        public void FrameAdvance()\n        {\n            frameIndex++;\n            if (frameIndex > LagFrames.Count)\n            {\n                LagFrames.Add(MainGUI.EMU.LagFrame);\n            }\n            else\n            {\n                LagFrames[frameIndex - 1] = MainGUI.EMU.LagFrame;\n            }\n            if (frameIndex > Resets.Count)\n            {\n                Resets.Add(false);\n            }\n            if (frameIndex > frameEmulated)\n            {\n                frameEmulated = frameIndex;\n            }\n            if (frameIndex > highestFrameEmulatedEver)\n            {\n                highestFrameEmulatedEver = frameIndex;\n            }\n            if (frameIndex == TimelineSavestates.Count)\n            {\n                // create a savestate for the previous frame.\n                if (cb_SavestateEveryFrame.Checked || frameIndex % AutoSavestateThreshold == 0)\n                {\n                    List<byte> state = MainGUI.EMU.SaveState();\n                    TimelineSavestates.Add(state);\n                }\n                else\n                {\n                    List<byte> state = new List<byte>();\n                    TimelineSavestates.Add(state);\n                }\n\n                if (TimelineSavestates[frameIndex].Count > 0)\n                {\n                    // if this savestate is not empty\n                    List<byte> state = new List<byte>();\n                    TimelineTempSavestates.Add(state);\n                }\n                else\n                {\n                    // if this savestate is empty\n                    List<byte> state = MainGUI.EMU.SaveState();\n                    TimelineTempSavestates.Add(state);\n                }\n\n                //TEMPRerecordTracker.Add(Rerecords);\n\n            }\n            else if (TimelineSavestates[frameIndex].Count != SavestateLength && cb_SavestateEveryFrame.Checked)\n            {\n                List<byte> state = MainGUI.EMU.SaveState();\n                TimelineSavestates[frameIndex] = state;\n                //TEMPRerecordTracker[frameIndex] = Rerecords;\n            }\n            TrimTempSavestates();\n\n            while (frameIndex >= Inputs.Count)\n            {\n                Inputs.Add(0);\n                Resets.Add(false);\n                MethodInvoker upd = delegate\n                {\n                    timelineScrollbar.Maximum = Inputs.Count + 38;\n                };\n                this.BeginInvoke(upd);\n            }\n            int row = frameIndex - TopFrame;\n\n            bool didFullRefresh = false;\n\n            if (cb_FollowCursor.Checked)\n            {\n                if (row >= TimelineGrid.Count || row > FollowDistance)\n                {\n                    TopFrame = frameIndex - FollowDistance;\n                    if (TopFrame != ScrollbarValue && TopFrame >= 0)\n                    {\n                        didFullRefresh = true;\n                        RefreshTimeline();\n                        MethodInvoker upd = delegate\n                        {\n                            ScrollbarValue = TopFrame;\n                            timelineScrollbar.Value = TopFrame;\n                        };\n                        this.Invoke(upd);\n                    }\n                }\n            }\n            if (!didFullRefresh)\n            {\n                UpdateTimelineRowStatus(row - 1);\n                RedrawTimelineRow(row - 1, false);\n                UpdateTimelineRowStatus(row);\n                RedrawTimelineRow(row, false);\n            }\n        }\n\n        private void loadTASToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            string InitDirectory = AppDomain.CurrentDomain.BaseDirectory;\n            if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @\"tas\\\"))\n            {\n                InitDirectory += @\"tas\\\";\n            }\n            OpenFileDialog ofd = new OpenFileDialog()\n            {\n                FileName = \"\",\n                Filter =\n                \"TriCNES TAS File (.3c2, .3c3)|*.3c2;*.3c3\" +\n                \"|Bizhawk Movie (.bk2)|*.bk2\" +\n                \"|Bizhawk TAStudio (.tasproj)|*.tasproj\" +\n                \"|FCEUX Movie (.fm2)|*.fm2\" +\n                \"|FCEUX TAS Editor (.fm3)|*.fm3\" +\n                \"|Famtastia Movie (.fmv)|*.fmv\" +\n                \"|Replay Device (.r08)|*.r08\" +\n                \"|All TAS Files (.3c2, .3c3, .bk2, .tasproj, .fm2, .fm3, .fmv, .r08)|*.3c2;*.3c3;*.bk2;*.tasproj;*.fm2;*.fm3;*.fmv;*.r08\",\n                Title = \"Select file\",\n                InitialDirectory = InitDirectory\n            };\n            if (ofd.ShowDialog() == DialogResult.OK)\n            {\n                frameIndex = 0;\n                Inputs = MainGUI.ParseTasFile(ofd.FileName, out Resets);\n                string extension = Path.GetExtension(ofd.FileName);\n                timelineScrollbar.Maximum = Inputs.Count + 38;\n                MainGUI.Timeline_PendingHardReset = true;\n\n                if (extension != \".3c3\")\n                {\n                    LagFrames = new List<bool>();\n                    TimelineSavestates = new List<List<byte>>();\n                    TimelineTempSavestates = new List<List<byte>>();\n                    // savestates are initialized in the Timeline_PendingArbitrarySavestate\n                    MainGUI.Timeline_PendingArbitrarySavestate = true;\n\n                    ScrollbarValue = 0;\n                    timelineScrollbar.Value = 0;\n                    TopFrame = 0;\n                    highestFrameEmulatedEver = 0;\n                    frameEmulated = 0;\n                }\n                if (extension == \".3c2\")\n                {\n                    byte[] b = File.ReadAllBytes(ofd.FileName); // Terribly inefficient to load the entire file a second time, but whatever.\n                    ClockFiltering = (b[0] & 1) == 1;\n                }\n                if (extension == \".3c3\")\n                {\n                    byte[] b = File.ReadAllBytes(ofd.FileName); // Terribly inefficient to load the entire file a second time, but whatever.\n                    ClockFiltering = (b[15] & 1) == 1;\n                }\n\n                RefreshTimeline();\n                GC.Collect();\n            }\n        }\n\n        private void saveTASToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            string InitDirectory = AppDomain.CurrentDomain.BaseDirectory;\n            if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @\"tas\\\"))\n            {\n                InitDirectory += @\"tas\\\";\n            }\n            SaveFileDialog sfd = new SaveFileDialog()\n            {\n                FileName = \"\",\n                Filter = \"TriCNES TAS File (.3c2)|*.3c2\",\n                Title = \"Save a .3c2 TAS File\",\n                InitialDirectory = InitDirectory\n            };\n            sfd.ShowDialog();\n\n            if (sfd.FileName != \"\")\n            {\n                FileStream fs = (FileStream)sfd.OpenFile();\n                // Determine if controller 2 is used.\n                bool UseController2 = false;\n                for (int i = 0; i < Inputs.Count; i++)\n                {\n                    if ((Inputs[i] & 0xFF00) != 0)\n                    {\n                        UseController2 = true;\n                        break;\n                    }\n                }\n                // Determine if the RESET button is used.\n                bool UseResets = false;\n                for (int i = 0; i < Inputs.Count; i++)\n                {\n                    if (i < Resets.Count && Resets[i])\n                    {\n                        UseResets = true;\n                        break;\n                    }\n                }\n                byte Header = 0;\n                Header |= (byte)(ClockFiltering ? 1 : 0);\n                Header |= (byte)(UseController2 ? 2 : 0);\n                Header |= (byte)(UseResets ? 4 : 0);\n                fs.WriteByte(Header);\n                for (int i = 0; i < Inputs.Count; i++)\n                {\n                    fs.WriteByte((byte)Inputs[i]);\n                    if (UseController2) { fs.WriteByte((byte)(Inputs[i] >> 8)); }\n                    if (UseResets) { fs.WriteByte((byte)(Resets[i] ? 0x80 : 0)); }\n                }\n                fs.Close();\n            }\n        }\n\n        private void saveWithSavestatesToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            string InitDirectory = AppDomain.CurrentDomain.BaseDirectory;\n            if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @\"tas\\\"))\n            {\n                InitDirectory += @\"tas\\\";\n            }\n            SaveFileDialog sfd = new SaveFileDialog()\n            {\n                FileName = \"\",\n                Filter = \"TriCNES TAS File (.3c3)|*.3c3\",\n                Title = \"Save a .3c3 TAS File\",\n                InitialDirectory = InitDirectory\n            };\n            sfd.ShowDialog();\n\n            if (sfd.FileName != \"\")\n            {\n                FileStream fs = (FileStream)sfd.OpenFile();\n                // save the length of the savestates\n                fs.WriteByte((byte)SavestateLength);\n                fs.WriteByte((byte)(SavestateLength >> 8));\n                fs.WriteByte((byte)(SavestateLength >> 16));\n                fs.WriteByte((byte)(SavestateLength >> 24));\n\n                // save the number of rerecords. (I personally don't care about this statistic, but other people do, so I'll add it!)\n                fs.WriteByte((byte)Rerecords);\n                fs.WriteByte((byte)(Rerecords >> 8));\n                fs.WriteByte((byte)(Rerecords >> 16));\n                fs.WriteByte((byte)(Rerecords >> 24));\n\n                // save the length of the TAS\n                fs.WriteByte((byte)Inputs.Count);\n                fs.WriteByte((byte)(Inputs.Count >> 8));\n                fs.WriteByte((byte)(Inputs.Count >> 16));\n                fs.WriteByte((byte)(Inputs.Count >> 24));\n\n                fs.WriteByte(0); // 3 currently unused bytes.\n                fs.WriteByte(0);\n                fs.WriteByte(0);\n\n                // Determine if controller 2 is used.\n                bool UseController2 = false;\n                for (int i = 0; i < Inputs.Count; i++)\n                {\n                    if ((Inputs[i] & 0xFF00) != 0)\n                    {\n                        UseController2 = true;\n                        break;\n                    }\n                }\n                // Determine if the RESET button is used.\n                bool UseResets = false;\n                for (int i = 0; i < Inputs.Count; i++)\n                {\n                    if (i < Resets.Count && Resets[i])\n                    {\n                        UseResets = true;\n                        break;\n                    }\n                }\n                byte Header15 = 0;\n                Header15 |= (byte)(ClockFiltering ? 1 : 0);\n                Header15 |= (byte)(UseController2 ? 2 : 0);\n                Header15 |= (byte)(UseResets ? 4 : 0);\n                fs.WriteByte(Header15);\n\n                for (int i = 0; i < Inputs.Count; i++)\n                {\n                    fs.WriteByte((byte)Inputs[i]);\n                    if (UseController2) { fs.WriteByte((byte)(Inputs[i] >> 8)); }\n                    if (UseResets) { fs.WriteByte((byte)((Resets[i] ? 0x80 : 0) | (i < LagFrames.Count ? (LagFrames[i] ? 1 : 0) : 0))); }\n                }\n\n                for (int i = 0; i < TimelineSavestates.Count; i++)\n                {\n                    if (TimelineSavestates[i].Count != 0)\n                    {\n                        // save the frame index\n                        fs.WriteByte((byte)i);\n                        fs.WriteByte((byte)(i >> 8));\n                        fs.WriteByte((byte)(i >> 16));\n                        fs.WriteByte((byte)(i >> 24));\n                        // save every byte of the savestate\n                        for (int j = 0; j < SavestateLength; j++)\n                        {\n                            fs.WriteByte(TimelineSavestates[i][j]);\n                        }\n                    }\n                }\n\n                fs.Close();\n            }\n        }\n\n        private void exportTor08ToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            string InitDirectory = AppDomain.CurrentDomain.BaseDirectory;\n            if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @\"tas\\\"))\n            {\n                InitDirectory += @\"tas\\\";\n            }\n            SaveFileDialog sfd = new SaveFileDialog()\n            {\n                FileName = \"\",\n                Filter = \"Replay Device (.r08)|*.r08\",\n                Title = \"Save a .r08 TAS File\",\n                InitialDirectory = InitDirectory\n            };\n            sfd.ShowDialog();\n\n            if (sfd.FileName != \"\")\n            {\n                FileStream fs = (FileStream)sfd.OpenFile();\n\n                if (ClockFiltering)\n                {\n                    // the .r08 file format is identical to my input list.\n                    for (int i = 0; i < Inputs.Count; i++)\n                    {\n                        fs.WriteByte((byte)Inputs[i]);\n                        fs.WriteByte((byte)(Inputs[i] >> 8));\n                    }\n                }\n                else\n                {\n                    if (LagFrames.Count < Inputs.Count)\n                    {\n                        MessageBox.Show(\"The .r08 exporter needs to know which frames are lag frames.\\nOnly frames that have been emulated on the timeline will be exported.\");\n                    }\n                    for (int i = 0; i < Inputs.Count; i++)\n                    {\n                        // the .r08 file format doesn't include lag frames.\n                        if (i < LagFrames.Count && !LagFrames[i])\n                        {\n                            fs.WriteByte((byte)Inputs[i]);\n                            fs.WriteByte((byte)(Inputs[i] >> 8));\n                        }\n                    }\n                }\n\n                fs.Close();\n            }\n\n        }\n\n        bool Paused = true;\n\n        private void b_play_Click(object sender, EventArgs e)\n        {\n            Paused = !Paused;\n            b_play.Text = Paused ? \"Paused\" : \"Running\";\n            MainGUI.Timeline_PendingResume = !Paused;\n            MainGUI.Timeline_PendingPause = Paused;\n            if (Paused)\n            {\n                GC.Collect();\n            }\n        }\n\n        private void deleteFrameToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n\n            Inputs.RemoveAt(frameIndex);\n            int HighlightedFrame = frameIndex;\n            if (HighlightedFrame < frameEmulated)\n            {\n                MarkStale(HighlightedFrame);\n            }\n            timelineScrollbar.Maximum = Inputs.Count + 38;\n            RefreshTimeline();\n        }\n\n        private void insertFrameToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            Inputs.Insert(frameIndex, 0);\n            int HighlightedFrame = frameIndex;\n            if (HighlightedFrame < frameEmulated)\n            {\n                MarkStale(HighlightedFrame);\n            }\n            timelineScrollbar.Maximum = Inputs.Count + 38;\n            RefreshTimeline();\n        }\n\n        public bool Player2()\n        {\n            return cb_player2.Checked;\n        }\n\n        private void truncateMovieToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            Inputs.RemoveRange(frameIndex + 1, Inputs.Count - (frameIndex + 1));\n            if (TimelineSavestates.Count > frameIndex)\n            {\n                TimelineSavestates.RemoveRange(frameIndex + 1, TimelineSavestates.Count - (frameIndex + 1));\n            }\n            if (TimelineTempSavestates.Count > frameIndex)\n            {\n                TimelineTempSavestates.RemoveRange(frameIndex + 1, TimelineTempSavestates.Count - (frameIndex + 1));\n            }\n            if (LagFrames.Count > frameIndex)\n            {\n                LagFrames.RemoveRange(frameIndex, LagFrames.Count - (frameIndex));\n            }\n            System.GC.Collect();\n            highestFrameEmulatedEver = frameIndex;\n            frameEmulated = frameIndex;\n            timelineScrollbar.Maximum = Inputs.Count + 38;\n            RefreshTimeline();\n        }\n\n        private void b_JumptoCursor_Click(object sender, EventArgs e)\n        {\n            int scroll = frameIndex - FollowDistance;\n            if (scroll < 0)\n            {\n                scroll = 0;\n            }\n            timelineScrollbar.Value = scroll;\n            TopFrame = scroll;\n            RefreshTimeline();\n        }\n\n        public void RefreshTimeline()\n        {\n            // redraw the entire timeline's bitmap.\n            for (int i = 0; i < 40; i++)\n            {\n                int frame = TopFrame + i;\n                RecalculateTimelineRow(i, frame < Inputs.Count ? Inputs[frame] : (ushort)0);\n                TimelineGrid[i][17].Checked = false;\n                if (frame >= 0 && frame < Resets.Count)\n                {\n                    TimelineGrid[i][17].Checked = Resets[frame];\n                }\n\n                RedrawTimelineRow(i, true);\n            }\n            MethodInvoker upd = delegate\n            {\n                pb_Timeline.Image = timelineBitmap;\n                pb_Timeline.Update();\n            };\n            this.Invoke(upd);\n        }\n        public void RedrawTimelineRow(int row, bool batch)\n        {\n            if (row < 0 || row >= TimelineGrid.Count)\n            {\n                return;\n            }\n\n            MethodInvoker upd = delegate\n            {\n                int rowp1 = row + 1;\n                Rectangle[] GridOverlay = new Rectangle[]\n                    {\n                        new Rectangle(0,rowp1*16,80,16),\n                        new Rectangle(80 + 16*0,rowp1*16,16,16),\n                        new Rectangle(80 + 16*1,rowp1*16,16,16),\n                        new Rectangle(80 + 16*2,rowp1*16,16,16),\n                        new Rectangle(80 + 16*3,rowp1*16,16,16),\n                        new Rectangle(80 + 16*4,rowp1*16,16,16),\n                        new Rectangle(80 + 16*5,rowp1*16,16,16),\n                        new Rectangle(80 + 16*6,rowp1*16,16,16),\n                        new Rectangle(80 + 16*7,rowp1*16,16,16),\n                        new Rectangle(80 + 16*8,rowp1*16,16,16),\n                        new Rectangle(80 + 16*9,rowp1*16,16,16),\n                        new Rectangle(80 + 16*10,rowp1*16,16,16),\n                        new Rectangle(80 + 16*11,rowp1*16,16,16),\n                        new Rectangle(80 + 16*12,rowp1*16,16,16),\n                        new Rectangle(80 + 16*13,rowp1*16,16,16),\n                        new Rectangle(80 + 16*14,rowp1*16,16,16),\n                        new Rectangle(80 + 16*15,rowp1*16,16,16),\n                        new Rectangle(80 + 16*16,rowp1*16,16,16)\n                    };\n                if (frameIndex - TopFrame == row)\n                {\n                    G.FillRectangle(Brush_HighlightedCell, new Rectangle(0, rowp1 * 16, 80 + 16 * 17, 16));\n                }\n                else if (!TimelineGrid[row][0].Emulated)\n                {\n                    G.FillRectangle(Brush_LeftColumn, new Rectangle(0, rowp1 * 16, 80, 16));\n                    G.FillRectangle(Brush_WhiteCellP1, new Rectangle(80, rowp1 * 16, 16 * 8, 16));\n                    G.FillRectangle(Brush_WhiteCellP2, new Rectangle(80 + 16 * 8, rowp1 * 16, 16 * 8, 16));\n                    G.FillRectangle(Brush_WhiteCellP1, new Rectangle(80 + 16 * 16, rowp1 * 16, 16, 16));\n                }\n                else if (TimelineGrid[row][0].Stale)\n                {\n                    G.FillRectangle(Brush_LeftColumn, new Rectangle(0, rowp1 * 16, 80, 16));\n                    G.FillRectangle(TimelineGrid[row][0].LagFrame ? Brush_RedCellP1_Stale : Brush_GreenCellP1_Stale, new Rectangle(80, rowp1 * 16, 16 * 8, 16));\n                    G.FillRectangle(TimelineGrid[row][0].LagFrame ? Brush_RedCellP2_Stale : Brush_GreenCellP2_Stale, new Rectangle(80 + 16 * 8, rowp1 * 16, 16 * 8, 16));\n                    G.FillRectangle(TimelineGrid[row][0].LagFrame ? Brush_RedCellP1_Stale : Brush_GreenCellP1_Stale, new Rectangle(80 + 16 * 16, rowp1 * 16, 16, 16));\n                }\n                else\n                {\n                    G.FillRectangle(TimelineSavestates[row + TopFrame].Count == SavestateLength ? Brush_LeftColumn_Saved : TimelineTempSavestates[row + TopFrame].Count == SavestateLength ? Brush_LeftColumn_TempSaved : Brush_LeftColumn, new Rectangle(0, rowp1 * 16, 80, 16));\n                    G.FillRectangle(TimelineGrid[row][0].LagFrame ? Brush_RedCellP1 : Brush_GreenCellP1, new Rectangle(80, rowp1 * 16, 16 * 8, 16));\n                    G.FillRectangle(TimelineGrid[row][0].LagFrame ? Brush_RedCellP2 : Brush_GreenCellP2, new Rectangle(80 + 16 * 8, rowp1 * 16, 16 * 8, 16));\n                    G.FillRectangle(TimelineGrid[row][0].LagFrame ? Brush_RedCellP1 : Brush_GreenCellP1, new Rectangle(80 + 16 * 16, rowp1 * 16, 16, 16));\n                }\n\n                G.DrawRectangles(Pens.Black, GridOverlay);\n                string rownum = (row + TopFrame).ToString();\n                //if(row + TopFrame < TEMPRerecordTracker.Count)\n                //{\n                //    rownum += \"   (\" + TEMPRerecordTracker[row + TopFrame].ToString() + \")\";\n                //}\n                G.DrawString(rownum, Font_Consolas, Brushes.Black, 0, rowp1 * 16);\n                if (TimelineGrid[row][1].Checked) { G.DrawString(\"A\", Font_Consolas, Brushes.Black, 80 + 16 * 0, rowp1 * 16); }\n                if (TimelineGrid[row][2].Checked) { G.DrawString(\"B\", Font_Consolas, Brushes.Black, 80 + 16 * 1, rowp1 * 16); }\n                if (TimelineGrid[row][3].Checked) { G.DrawString(\"s\", Font_Consolas, Brushes.Black, 80 + 16 * 2, rowp1 * 16); }\n                if (TimelineGrid[row][4].Checked) { G.DrawString(\"S\", Font_Consolas, Brushes.Black, 80 + 16 * 3, rowp1 * 16); }\n                if (TimelineGrid[row][5].Checked) { G.DrawString(\"U\", Font_Consolas, Brushes.Black, 80 + 16 * 4, rowp1 * 16); }\n                if (TimelineGrid[row][6].Checked) { G.DrawString(\"D\", Font_Consolas, Brushes.Black, 80 + 16 * 5, rowp1 * 16); }\n                if (TimelineGrid[row][7].Checked) { G.DrawString(\"L\", Font_Consolas, Brushes.Black, 80 + 16 * 6, rowp1 * 16); }\n                if (TimelineGrid[row][8].Checked) { G.DrawString(\"R\", Font_Consolas, Brushes.Black, 80 + 16 * 7, rowp1 * 16); }\n                if (TimelineGrid[row][9].Checked) { G.DrawString(\"A\", Font_Consolas, Brushes.Black, 80 + 16 * 8, rowp1 * 16); }\n                if (TimelineGrid[row][10].Checked) { G.DrawString(\"B\", Font_Consolas, Brushes.Black, 80 + 16 * 9, rowp1 * 16); }\n                if (TimelineGrid[row][11].Checked) { G.DrawString(\"s\", Font_Consolas, Brushes.Black, 80 + 16 * 10, rowp1 * 16); }\n                if (TimelineGrid[row][12].Checked) { G.DrawString(\"S\", Font_Consolas, Brushes.Black, 80 + 16 * 11, rowp1 * 16); }\n                if (TimelineGrid[row][13].Checked) { G.DrawString(\"U\", Font_Consolas, Brushes.Black, 80 + 16 * 12, rowp1 * 16); }\n                if (TimelineGrid[row][14].Checked) { G.DrawString(\"D\", Font_Consolas, Brushes.Black, 80 + 16 * 13, rowp1 * 16); }\n                if (TimelineGrid[row][15].Checked) { G.DrawString(\"L\", Font_Consolas, Brushes.Black, 80 + 16 * 14, rowp1 * 16); }\n                if (TimelineGrid[row][16].Checked) { G.DrawString(\"R\", Font_Consolas, Brushes.Black, 80 + 16 * 15, rowp1 * 16); }\n                if (TimelineGrid[row][17].Checked) { G.DrawString(\"r\", Font_Consolas, Brushes.Black, 80 + 16 * 16, rowp1 * 16); }\n                if (!batch)\n                {\n                    pb_Timeline.Image = timelineBitmap;\n                    pb_Timeline.Update();\n                }\n            };\n            this.BeginInvoke(upd);\n\n\n        }\n        public void RecalculateTimelineRow(int row, ushort input)\n        {\n            // redraw one row of the timeline\n            if (row < 0 || row >= TimelineGrid.Count)\n            {\n                return;\n            }\n            TimelineGrid[row][8].Checked = (input & 1) == 1;\n            input >>= 1;\n            TimelineGrid[row][7].Checked = (input & 1) == 1;\n            input >>= 1;\n            TimelineGrid[row][6].Checked = (input & 1) == 1;\n            input >>= 1;\n            TimelineGrid[row][5].Checked = (input & 1) == 1;\n            input >>= 1;\n            TimelineGrid[row][4].Checked = (input & 1) == 1;\n            input >>= 1;\n            TimelineGrid[row][3].Checked = (input & 1) == 1;\n            input >>= 1;\n            TimelineGrid[row][2].Checked = (input & 1) == 1;\n            input >>= 1;\n            TimelineGrid[row][1].Checked = (input & 1) == 1;\n            input >>= 1;\n            TimelineGrid[row][16].Checked = (input & 1) == 1;\n            input >>= 1;\n            TimelineGrid[row][15].Checked = (input & 1) == 1;\n            input >>= 1;\n            TimelineGrid[row][14].Checked = (input & 1) == 1;\n            input >>= 1;\n            TimelineGrid[row][13].Checked = (input & 1) == 1;\n            input >>= 1;\n            TimelineGrid[row][12].Checked = (input & 1) == 1;\n            input >>= 1;\n            TimelineGrid[row][11].Checked = (input & 1) == 1;\n            input >>= 1;\n            TimelineGrid[row][10].Checked = (input & 1) == 1;\n            input >>= 1;\n            TimelineGrid[row][9].Checked = (input & 1) == 1;\n\n            UpdateTimelineRowStatus(row);\n        }\n        public void UpdateTimelineRowStatus(int row)\n        {\n            if (row < 0 || row >= TimelineGrid.Count)\n            {\n                return;\n            }\n\n            // redraw one row of the timeline\n            int frame = (TopFrame + row);\n\n            bool Emulated = frame < highestFrameEmulatedEver;\n            bool Stale = Emulated && (frame > frameEmulated);\n            bool LagFrame = false;\n            if (LagFrames.Count > frame)\n            {\n                LagFrame = Emulated && (LagFrames[frame]);\n            }\n            TimelineGrid[row][0].Emulated = Emulated;\n            TimelineGrid[row][0].Stale = Stale;\n            TimelineGrid[row][0].LagFrame = LagFrame;\n        }\n        int FollowDistance = 20;\n        private void tb_FollowDistance_Scroll(object sender, EventArgs e)\n        {\n            FollowDistance = tb_FollowDistance.Value;\n        }\n\n        public bool SavestateEveryFrame()\n        {\n            return cb_SavestateEveryFrame.Checked;\n        }\n        public bool RecordInputs()\n        {\n            return cb_RecordInputs.Checked;\n        }\n        List<byte> GrabMostRecentSavestate()\n        {\n            int l = TimelineSavestates[frameIndex].Count;\n            if (l != SavestateLength)\n            {\n                l = TimelineTempSavestates[frameIndex].Count;\n                if (l == SavestateLength)\n                {\n                    return TimelineTempSavestates[frameIndex];\n                }\n            }\n            bool temp = false;\n            while (l != SavestateLength)\n            {\n                frameIndex--;\n                l = TimelineSavestates[frameIndex].Count;\n                if (l != SavestateLength)\n                {\n                    l = TimelineTempSavestates[frameIndex].Count;\n                    if (l == SavestateLength)\n                    {\n                        temp = true;\n                        break;\n                    }\n                }\n            }\n            return temp ? TimelineTempSavestates[frameIndex] : TimelineSavestates[frameIndex];\n        }\n\n        List<byte> GrabMostRecentSavestate(int TargetFrame, out bool HitTargetFrame)\n        {\n            if (frameIndex == TargetFrame)\n            {\n                HitTargetFrame = true;\n                return null;\n            }\n            bool temp = false;\n            int l = TimelineSavestates[frameIndex].Count;\n            if (l != SavestateLength)\n            {\n                l = TimelineTempSavestates[frameIndex].Count;\n                if (l == SavestateLength)\n                {\n                    HitTargetFrame = false;\n                    return TimelineTempSavestates[frameIndex];\n                }\n            }\n            while (l != SavestateLength)\n            {\n                frameIndex--;\n                if (frameIndex == TargetFrame)\n                {\n                    HitTargetFrame = true;\n                    return null;\n                }\n                l = TimelineSavestates[frameIndex].Count;\n                if (l != SavestateLength)\n                {\n                    l = TimelineTempSavestates[frameIndex].Count;\n                    if (l == SavestateLength)\n                    {\n                        temp = true;\n                        break;\n                    }\n                }\n            }\n            HitTargetFrame = false;\n            return temp ? TimelineTempSavestates[frameIndex] : TimelineSavestates[frameIndex];\n        }\n\n        private void savestateThisFrameToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            if (frameIndex == TimelineSavestates.Count)\n            {\n                List<byte> state = MainGUI.EMU.SaveState();\n                TimelineSavestates.Add(state);\n                if (TimelineTempSavestates[frameIndex].Count > 0)\n                {\n                    TimelineTempSavestates[frameIndex] = new List<byte>(); // remove temp savestate for this frame\n                }\n            }\n            else\n            {\n                List<byte> state = MainGUI.EMU.SaveState();\n                TimelineSavestates[frameIndex] = state;\n                if (TimelineTempSavestates[frameIndex].Count > 0)\n                {\n                    TimelineTempSavestates[frameIndex] = new List<byte>(); // remove temp savestate for this frame\n                }\n                GC.Collect();\n            }\n        }\n\n        public void TrimTempSavestates()\n        {\n            int deletion = frameIndex - TempSavestates;\n            if (deletion >= 0 && deletion < TimelineTempSavestates.Count && TimelineTempSavestates[deletion].Count > 0)\n            {\n                TimelineTempSavestates[deletion] = new List<byte>(); // remove temp savestate for this frame\n                int row = deletion - TopFrame;\n                if (row >= 0 && row < 40)\n                {\n                    UpdateTimelineRowStatus(row);\n                    RedrawTimelineRow(row, false);\n                }\n            }\n        }\n\n        private void tb_FilterForNumbers(object sender, KeyPressEventArgs e)\n        {\n            if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar))\n            {\n                e.Handled = true;\n            }\n        }\n\n        private void tb_AutoSavestateThreshold_TextChanged(object sender, EventArgs e)\n        {\n            int i = 0;\n            if (int.TryParse(tb_AutoSavestateThreshold.Text, out i))\n            {\n                AutoSavestateThreshold = i;\n            }\n\n        }\n\n        private void tb_TempSavestates_TextChanged(object sender, EventArgs e)\n        {\n            int i = 0;\n            if (int.TryParse(tb_TempSavestates.Text, out i))\n            {\n                TempSavestates = i;\n            }\n        }\n\n        public void ChangePlayPauseButtonText(string str)\n        {\n            MethodInvoker upd = delegate\n            {\n                b_play.Text = str;\n                b_play.Update();\n            };\n            this.Invoke(upd);\n        }\n\n        public bool ClockFiltering;\n        private void perVBlankToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            perVBlankToolStripMenuItem.Checked = true;\n            perControllerStrobeToolStripMenuItem.Checked = false;\n            ClockFiltering = false;\n            // reset the TAS and mark everything as stale!\n            ResetTASAndMarkEverythingStale();\n            MainGUI.Timeline_PendingClockFiltering = false;\n            RefreshTopOfTimeline();\n        }\n\n        private void perControllerStrobeToolStripMenuItem_Click(object sender, EventArgs e)\n        {\n            perVBlankToolStripMenuItem.Checked = false;\n            perControllerStrobeToolStripMenuItem.Checked = true;\n            ClockFiltering = true;\n            ResetTASAndMarkEverythingStale();\n            MainGUI.Timeline_PendingClockFiltering = true;\n            RefreshTopOfTimeline();\n        }\n\n        void ResetTASAndMarkEverythingStale()\n        {\n            frameIndex = 0;\n            timelineScrollbar.Maximum = Inputs.Count + 38;\n            MainGUI.Timeline_PendingHardReset = true;\n\n            LagFrames = new List<bool>();\n            TimelineSavestates = new List<List<byte>>();\n            TimelineTempSavestates = new List<List<byte>>();\n            // savestates are initialized in the Timeline_PendingArbitrarySavestate\n            MainGUI.Timeline_PendingArbitrarySavestate = true;\n\n            ScrollbarValue = 0;\n            timelineScrollbar.Value = 0;\n            TopFrame = 0;\n            highestFrameEmulatedEver = 0;\n            frameEmulated = 0;\n\n            RefreshTimeline();\n        }\n    }\n}\n"
  },
  {
    "path": "forms/TriCTASTimeline.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <metadata name=\"menuStrip1.TrayLocation\" type=\"System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n    <value>17, 17</value>\n  </metadata>\n  <metadata name=\"menuStrip1.Locked\" type=\"System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\">\n    <value>True</value>\n  </metadata>\n  <metadata name=\"contextMenuStrip_Timeline.TrayLocation\" type=\"System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n    <value>132, 17</value>\n  </metadata>\n  <metadata name=\"Tooltip_.TrayLocation\" type=\"System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n    <value>331, 17</value>\n  </metadata>\n  <data name=\"tb_TempSavestates.ToolTip\" xml:space=\"preserve\">\n    <value>In order to move backwards on the timeline, the emulator needs to keep savestetes for earlier frames.\nSavestates require copies of every variable in the emulator, and can be a bit RAM consuming.\nThese temporary savestates will record the previous 'n' frames before being deleted, allowing you to fix mistakes in the previous 'n' frames.\nYou could also choose to create a savestate on every frame if you would prefer.\n</value>\n  </data>\n  <data name=\"label_TempSavestates.ToolTip\" xml:space=\"preserve\">\n    <value>In order to move backwards on the timeline, the emulator needs to keep savestetes for earlier frames.\nSavestates require copies of every variable in the emulator, and can be a bit RAM consuming.\nThese temporary savestates will record the previous 'n' frames before being deleted, allowing you to fix mistakes in the previous 'n' frames.\nYou could also choose to create a savestate on every frame if you would prefer.</value>\n  </data>\n  <assembly alias=\"System.Drawing\" name=\"System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\" />\n  <data name=\"$this.Icon\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAA/wAA\n        AP8AAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAA\n        AP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA\n        AAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAA\n        AP8AAAD/AAAA/wAAAP8AAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAAAAAA\n        AAD///////////////////////////////8AAAAAAAAAAAAAAP8AAAD/AAAAAAAAAAD/////////////\n        //////////////////8AAAAAAAAAAAAAAP8AAAD/////////////////////////////////AAAAAAAA\n        AAAAAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//\n        /////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAA\n        AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////\n        ////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA////////\n        //8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAA\n        AP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAA\n        AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//\n        ////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAA\n        AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAA\n        AAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA////////\n        //8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA\n        AAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA\n        AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAA\n        AP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAA\n        AAAAAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//\n        ////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAA\n        AP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA\n        AAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/////////\n        //8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD//////////////////////wAA\n        AP8AAAD/AAAAAAAAAAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAA\n        AAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAAAAD/////////////\n        ////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/////////\n        //8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD///////////8AAAAAAAAAAAAA\n        AAAAAAAA//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////\n        //8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////////8AAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////////\n        /////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////////////////////////wAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAA///////////////////////////////////////////A8D8DwPA/AwPA\n        zAwDwMwMww8A8MMPAPDDDwDwww8A8MMPAPDDDwDwww8A8MMPAPADMDMDAzAzA8/A/A/PwPwP////////\n        //////////////////////////////////8=\n</value>\n  </data>\n</root>"
  },
  {
    "path": "forms/TriCTraceLogger.Designer.cs",
    "content": "﻿namespace TriCNES\n{\n    partial class TriCTraceLogger\n    {\n        /// <summary>\n        /// Required designer variable.\n        /// </summary>\n        private System.ComponentModel.IContainer components = null;\n\n        /// <summary>\n        /// Clean up any resources being used.\n        /// </summary>\n        /// <param name=\"disposing\">true if managed resources should be disposed; otherwise, false.</param>\n        protected override void Dispose(bool disposing)\n        {\n            if (disposing && (components != null))\n            {\n                components.Dispose();\n            }\n            base.Dispose(disposing);\n        }\n\n        #region Windows Form Designer generated code\n\n        /// <summary>\n        /// Required method for Designer support - do not modify\n        /// the contents of this method with the code editor.\n        /// </summary>\n        private void InitializeComponent()\n        {\n            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TriCTraceLogger));\n            this.b_ToggleButton = new System.Windows.Forms.CheckBox();\n            this.groupBox1 = new System.Windows.Forms.GroupBox();\n            this.rtb_TraceLog = new System.Windows.Forms.RichTextBox();\n            this.cb_LogInRange = new System.Windows.Forms.CheckBox();\n            this.tb_RangeLow = new System.Windows.Forms.TextBox();\n            this.tb_RangeHigh = new System.Windows.Forms.TextBox();\n            this.cb_ClearEveryFrame = new System.Windows.Forms.CheckBox();\n            this.cb_LogPPU = new System.Windows.Forms.CheckBox();\n            this.groupBox1.SuspendLayout();\n            this.SuspendLayout();\n            // \n            // b_ToggleButton\n            // \n            this.b_ToggleButton.Appearance = System.Windows.Forms.Appearance.Button;\n            this.b_ToggleButton.AutoSize = true;\n            this.b_ToggleButton.Location = new System.Drawing.Point(12, 497);\n            this.b_ToggleButton.Name = \"b_ToggleButton\";\n            this.b_ToggleButton.Size = new System.Drawing.Size(80, 23);\n            this.b_ToggleButton.TabIndex = 0;\n            this.b_ToggleButton.Text = \"Start Logging\";\n            this.b_ToggleButton.UseVisualStyleBackColor = true;\n            this.b_ToggleButton.CheckedChanged += new System.EventHandler(this.b_ToggleButton_CheckedChanged);\n            // \n            // groupBox1\n            // \n            this.groupBox1.Controls.Add(this.rtb_TraceLog);\n            this.groupBox1.Location = new System.Drawing.Point(12, 27);\n            this.groupBox1.Name = \"groupBox1\";\n            this.groupBox1.Size = new System.Drawing.Size(931, 464);\n            this.groupBox1.TabIndex = 1;\n            this.groupBox1.TabStop = false;\n            this.groupBox1.Text = \"Trace Log\";\n            // \n            // rtb_TraceLog\n            // \n            this.rtb_TraceLog.DetectUrls = false;\n            this.rtb_TraceLog.Font = new System.Drawing.Font(\"Consolas\", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));\n            this.rtb_TraceLog.Location = new System.Drawing.Point(7, 20);\n            this.rtb_TraceLog.Name = \"rtb_TraceLog\";\n            this.rtb_TraceLog.Size = new System.Drawing.Size(918, 438);\n            this.rtb_TraceLog.TabIndex = 56;\n            this.rtb_TraceLog.Text = \"\";\n            this.rtb_TraceLog.WordWrap = false;\n            // \n            // cb_LogInRange\n            // \n            this.cb_LogInRange.AutoSize = true;\n            this.cb_LogInRange.Location = new System.Drawing.Point(165, 498);\n            this.cb_LogInRange.Name = \"cb_LogInRange\";\n            this.cb_LogInRange.Size = new System.Drawing.Size(139, 17);\n            this.cb_LogInRange.TabIndex = 2;\n            this.cb_LogInRange.Text = \"Only Log Within Range:\";\n            this.cb_LogInRange.UseVisualStyleBackColor = true;\n            this.cb_LogInRange.CheckedChanged += new System.EventHandler(this.cb_LogInRange_CheckedChanged);\n            // \n            // tb_RangeLow\n            // \n            this.tb_RangeLow.Enabled = false;\n            this.tb_RangeLow.Location = new System.Drawing.Point(298, 495);\n            this.tb_RangeLow.MaxLength = 4;\n            this.tb_RangeLow.Name = \"tb_RangeLow\";\n            this.tb_RangeLow.ReadOnly = true;\n            this.tb_RangeLow.Size = new System.Drawing.Size(32, 20);\n            this.tb_RangeLow.TabIndex = 3;\n            this.tb_RangeLow.Text = \"0000\";\n            this.tb_RangeLow.TextChanged += new System.EventHandler(this.tb_RangeLow_TextChanged);\n            // \n            // tb_RangeHigh\n            // \n            this.tb_RangeHigh.Enabled = false;\n            this.tb_RangeHigh.Location = new System.Drawing.Point(336, 495);\n            this.tb_RangeHigh.MaxLength = 4;\n            this.tb_RangeHigh.Name = \"tb_RangeHigh\";\n            this.tb_RangeHigh.ReadOnly = true;\n            this.tb_RangeHigh.Size = new System.Drawing.Size(32, 20);\n            this.tb_RangeHigh.TabIndex = 4;\n            this.tb_RangeHigh.Text = \"FFFF\";\n            this.tb_RangeHigh.TextChanged += new System.EventHandler(this.tb_RangeHigh_TextChanged);\n            // \n            // cb_ClearEveryFrame\n            // \n            this.cb_ClearEveryFrame.AutoSize = true;\n            this.cb_ClearEveryFrame.Checked = true;\n            this.cb_ClearEveryFrame.CheckState = System.Windows.Forms.CheckState.Checked;\n            this.cb_ClearEveryFrame.Location = new System.Drawing.Point(165, 521);\n            this.cb_ClearEveryFrame.Name = \"cb_ClearEveryFrame\";\n            this.cb_ClearEveryFrame.Size = new System.Drawing.Size(133, 17);\n            this.cb_ClearEveryFrame.TabIndex = 5;\n            this.cb_ClearEveryFrame.Text = \"Clear Log Every Frame\";\n            this.cb_ClearEveryFrame.UseVisualStyleBackColor = true;\n            // \n            // cb_LogPPU\n            // \n            this.cb_LogPPU.AutoSize = true;\n            this.cb_LogPPU.Location = new System.Drawing.Point(165, 548);\n            this.cb_LogPPU.Name = \"cb_LogPPU\";\n            this.cb_LogPPU.Size = new System.Drawing.Size(103, 17);\n            this.cb_LogPPU.TabIndex = 6;\n            this.cb_LogPPU.Text = \"Log PPU Cycles\";\n            this.cb_LogPPU.UseVisualStyleBackColor = true;\n            // \n            // TriCTraceLogger\n            // \n            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);\n            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;\n            this.ClientSize = new System.Drawing.Size(953, 577);\n            this.Controls.Add(this.cb_LogPPU);\n            this.Controls.Add(this.cb_ClearEveryFrame);\n            this.Controls.Add(this.tb_RangeHigh);\n            this.Controls.Add(this.tb_RangeLow);\n            this.Controls.Add(this.cb_LogInRange);\n            this.Controls.Add(this.groupBox1);\n            this.Controls.Add(this.b_ToggleButton);\n            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;\n            this.Icon = ((System.Drawing.Icon)(resources.GetObject(\"$this.Icon\")));\n            this.MaximizeBox = false;\n            this.MaximumSize = new System.Drawing.Size(969, 616);\n            this.MinimizeBox = false;\n            this.MinimumSize = new System.Drawing.Size(969, 616);\n            this.Name = \"TriCTraceLogger\";\n            this.Text = \"Trace Logger\";\n            this.groupBox1.ResumeLayout(false);\n            this.ResumeLayout(false);\n            this.PerformLayout();\n\n        }\n\n        #endregion\n\n        private System.Windows.Forms.CheckBox b_ToggleButton;\n        private System.Windows.Forms.GroupBox groupBox1;\n        private System.Windows.Forms.RichTextBox rtb_TraceLog;\n        private System.Windows.Forms.CheckBox cb_LogInRange;\n        private System.Windows.Forms.TextBox tb_RangeLow;\n        private System.Windows.Forms.TextBox tb_RangeHigh;\n        private System.Windows.Forms.CheckBox cb_ClearEveryFrame;\n        private System.Windows.Forms.CheckBox cb_LogPPU;\n    }\n}"
  },
  {
    "path": "forms/TriCTraceLogger.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Data;\nusing System.Drawing;\nusing System.Linq;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System.Windows.Forms;\n\nnamespace TriCNES\n{\n    public partial class TriCTraceLogger : Form\n    {\n        public TriCNESGUI MainGUI;\n        public bool Logging;\n        public TriCTraceLogger()\n        {\n            InitializeComponent();\n            FormClosing += new FormClosingEventHandler(TriCTraceLogger_Closing);\n        }\n\n        private void TriCTraceLogger_Closing(Object sender, FormClosingEventArgs e)\n        {\n            MainGUI.TraceLogger = null;\n        }\n\n        public void Init()\n        {\n            rtb_TraceLog.SelectionTabs = new int[] { 0, 56, 56 * 2, 56 * 3, 56 * 4, 56 * 5, 56 * 6, 56 * 7, 56 * 8, 56 * 9, 56 * 10 };\n        }\n        String Log;\n        public void Update()\n        {\n            if (MainGUI.EMU.DebugLog != null)\n            {\n                Log = MainGUI.EMU.DebugLog.ToString();\n                MethodInvoker upd = delegate\n                {\n                    rtb_TraceLog.Text = Log;\n                };\n                try\n                {\n                    this.Invoke(upd);\n                }\n                catch (Exception e)\n                {\n\n                }\n            }\n        }\n\n        private void b_ToggleButton_CheckedChanged(object sender, EventArgs e)\n        {\n            Logging = b_ToggleButton.Checked;\n            b_ToggleButton.Text = Logging ? \"Stop Logging\" : \"Start Logging\";\n        }\n\n        private void cb_LogInRange_CheckedChanged(object sender, EventArgs e)\n        {\n            tb_RangeHigh.ReadOnly = !cb_LogInRange.Checked;\n            tb_RangeHigh.Enabled = cb_LogInRange.Checked;\n            tb_RangeLow.ReadOnly = !cb_LogInRange.Checked;\n            tb_RangeLow.Enabled = cb_LogInRange.Checked;\n        }\n\n        private void tb_RangeLow_TextChanged(object sender, EventArgs e)\n        {\n            RangeLow = 0;\n            ushort.TryParse(tb_RangeLow.Text, System.Globalization.NumberStyles.HexNumber, null, out RangeLow);\n        }\n\n        private void tb_RangeHigh_TextChanged(object sender, EventArgs e)\n        {\n            RangeHigh = 0xFFFF;\n            ushort.TryParse(tb_RangeHigh.Text, System.Globalization.NumberStyles.HexNumber, null, out RangeHigh);\n        }\n        public ushort RangeLow;\n        public ushort RangeHigh;\n\n        public bool OnlyDebugInRange()\n        {\n            return cb_LogInRange.Checked;\n        }\n        public bool ClearEveryFrame()\n        {\n            return cb_ClearEveryFrame.Checked;\n        }\n\n        public bool LogPPUCycles()\n        {\n            return cb_LogPPU.Checked;\n        }\n    }\n}\n"
  },
  {
    "path": "forms/TriCTraceLogger.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <assembly alias=\"System.Drawing\" name=\"System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\" />\n  <data name=\"$this.Icon\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n    <value>\n        AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAA/wAA\n        AP8AAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA/wAA\n        AP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA\n        AAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/wAA\n        AP8AAAD/AAAA/wAAAP8AAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAAAAAA\n        AAD///////////////////////////////8AAAAAAAAAAAAAAP8AAAD/AAAAAAAAAAD/////////////\n        //////////////////8AAAAAAAAAAAAAAP8AAAD/////////////////////////////////AAAAAAAA\n        AAAAAAAAAAAAAP///////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//\n        /////////////////////////////wAAAAAAAAAAAAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAA\n        AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////\n        ////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA////////\n        //8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAA\n        AP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAA\n        AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//\n        ////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAA\n        AP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAAAA\n        AAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA////////\n        //8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA\n        AAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD///////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAA\n        AAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAAAP8AAAD/AAAAAAAAAAD//////////wAA\n        AP8AAAD/AAAAAAAAAAAAAAAAAAAAAP//////////AAAA/wAAAP///////////wAAAP8AAAD/AAAAAAAA\n        AAAAAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAA/wAAAP8AAAAAAAAAAP//\n        ////////AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA////////////AAAA/wAA\n        AP8AAAAAAAAAAAAAAAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAA//////////8AAAD/AAAA/wAA\n        AAAAAAAA//////////8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD/////////\n        //8AAAD/AAAA/wAAAAAAAAAAAAAAAAAAAAD//////////wAAAP8AAAD//////////////////////wAA\n        AP8AAAD/AAAAAAAAAAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAA\n        AAD//////////wAAAAAAAAAAAAAA/wAAAP8AAAD/AAAA////////////AAAAAAAAAAD/////////////\n        ////////AAAA/wAAAP8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD/////////\n        //8AAAAAAAAAAP//////////AAAAAAAAAAAAAAD/AAAA/wAAAP8AAAD///////////8AAAAAAAAAAAAA\n        AAAAAAAA//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////\n        //8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////////8AAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////////////////\n        /////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////////////////////////////wAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n        AAAAAAAAAAAAAAAAAAAAAAAA///////////////////////////////////////////A8D8DwPA/AwPA\n        zAwDwMwMww8A8MMPAPDDDwDwww8A8MMPAPDDDwDwww8A8MMPAPADMDMDAzAzA8/A/A/PwPwP////////\n        //////////////////////////////////8=\n</value>\n  </data>\n</root>"
  },
  {
    "path": "mappers/Mapper_AOROM.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Net;\n\nnamespace TriCNES.mappers\n{\n    public class Mapper_AOROM : Mapper\n    {\n        // ines Mapper 7\n        public byte Mapper_7_BankSelect;\n        public override void FetchPRG(ushort Address, bool Observe)\n        {\n            bool notFloating = false;\n            byte data = 0;\n            if (!Observe) { dataPinsAreNotFloating = false; } else { observedDataPinsAreNotFloating = false; }\n            // Observing can happen on a different thread, so we need to ensure that observing doesn't overwrite the data bus or floating pins status.\n\n            if (Address >= 0x8000)\n            {\n                dataPinsAreNotFloating = true;\n                ushort tempo = (ushort)(Address & 0x7FFF);\n                dataBus = Cart.PRGROM[(0x8000 * (Mapper_7_BankSelect & 0x07) + tempo) & (Cart.PRGROM.Length - 1)];\n            }\n            // AOROM doesn't have any PRG RAM\n\n            if (notFloating)\n            {\n                EndFetchPRG(Observe, data);\n            }\n            return;\n        }\n        public override void StorePRG(ushort Address, byte Input)\n        {\n            if (Address >= 0x8000)\n            {\n                Mapper_7_BankSelect = Input;\n            }\n        }\n        public override ushort MirrorNametable(ushort Address)\n        {\n            if ((Mapper_7_BankSelect & 0x10) == 0) // show nametable 0\n            {\n                Address &= 0x33FF;\n            }\n            else // show nametable 1\n            {\n                Address &= 0x33FF;\n                Address |= 0x400;\n            }\n            return Address;\n        }\n        public override List<byte> SaveMapperRegisters()\n        {\n            List<byte> State = new List<byte>();\n            foreach (Byte b in Cart.PRGRAM) { State.Add(b); }\n            foreach (Byte b in Cart.CHRRAM) { State.Add(b); }\n            State.Add(Mapper_7_BankSelect);\n            return State;\n        }\n        public override void LoadMapperRegisters(List<byte> State, int startIndex, out int exitIndex)\n        {\n            int p = startIndex;\n            for (int i = 0; i < Cart.PRGRAM.Length; i++) { Cart.PRGRAM[i] = State[p++]; }\n            for (int i = 0; i < Cart.CHRRAM.Length; i++) { Cart.CHRRAM[i] = State[p++]; }\n            Mapper_7_BankSelect = State[p++];\n            exitIndex = p;\n        }\n    }\n}"
  },
  {
    "path": "mappers/Mapper_CNROM.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace TriCNES.mappers\n{\n    public class Mapper_CNROM : Mapper\n    {\n        // ines Mapper 3\n        public byte Mapper_3_CHRBank;\n        public override void StorePRG(ushort Address, byte Input)\n        {\n            if (Address >= 0x8000)\n            {\n                Mapper_3_CHRBank = (byte)(Input & 0x3);\n            }\n        }\n        public override byte FetchCHR(ushort Address, bool Observe)\n        {\n            return Cart.CHRROM[(Mapper_3_CHRBank * 0x2000 + Address) & (Cart.CHRROM.Length - 1)];\n        }\n        public override List<byte> SaveMapperRegisters()\n        {\n            List<byte> State = new List<byte>();\n            foreach (Byte b in Cart.PRGRAM) { State.Add(b); }\n            foreach (Byte b in Cart.CHRRAM) { State.Add(b); }\n            State.Add(Mapper_3_CHRBank);\n            return State;\n        }\n        public override void LoadMapperRegisters(List<byte> State, int startIndex, out int exitIndex)\n        {\n            int p = startIndex;\n            for (int i = 0; i < Cart.PRGRAM.Length; i++) { Cart.PRGRAM[i] = State[p++]; }\n            for (int i = 0; i < Cart.CHRRAM.Length; i++) { Cart.CHRRAM[i] = State[p++]; }\n            Mapper_3_CHRBank = State[p++];\n            exitIndex = p;\n        }\n    }\n}"
  },
  {
    "path": "mappers/Mapper_FDS.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace TriCNES.mappers\n{\n    public class Mapper_FDS : Mapper\n    {\n        // The Famicom Disk System\n        public byte[] FDS_BIOS;\n\n        public byte FDS_4023_IOEnable;\n        public byte FDS_4025_Control;\n\n        public Mapper_FDS(byte[] fds_bios)\n        {\n            FDS_BIOS = fds_bios;\n        }\n\n        public override void FetchPRG(ushort Address, bool Observe)\n        {\n            bool notFloating = false;\n            byte data = 0;\n            if (!Observe) { dataPinsAreNotFloating = false; } else { observedDataPinsAreNotFloating = false; }\n            // Observing can happen on a different thread, so we need to ensure that observing doesn't overwrite the data bus or floating pins status.\n\n            if (Address >= 0xE000)\n            {\n                // read from the FDS BIOS\n                notFloating = true;\n                data = FDS_BIOS[Address & 0x1FFF];\n            }\n            else if (Address >= 0x6000)\n            {\n                // read from the FDS PRG RAM\n                notFloating = true;\n                data = Cart.PRGRAM[Address-0x6000];\n            }\n            else if (Address >= 4030 && Address <= 0x403F)\n            {\n                // Read from the FDS Registers\n                Address &= 0xF;\n                switch (Address)\n                {\n                    default: break;\n                    case 0:\n                        {\n                            // FDS Status ($4030)\n                            notFloating = true;\n                            data = 0;\n\n                            data |= (byte)((FDS_4025_Control >> 3) & 1); // 4030.3 = 4025.3\n\n                            data |= (byte)(Cart.FDS.Status_ByteTransferFlag ? 0x80 : 0); // 4030.7 = Byte Transfer Flag\n\n\n                        }\n                        break;\n                    case 1:\n                        {\n                            // Disk Data Input ($4031)\n                            notFloating = true;\n                            data = Cart.FDS.ShiftRegisterLatch;\n                            Cart.FDS.Status_ByteTransferFlag = false;\n                            Cart.Emu.IRQ_LevelDetector = false; //acknowledge the IRQ\n                        }\n                        break;\n                    case 2:\n                        {\n                            // Disk Drive Status ($4032)\n\n                        }\n                        break;\n                    case 3:\n                        {\n                            // External Connector Input ($4033)\n                            notFloating = true;\n                            data = 0x80; // The battery is good.\n                        }\n                        break;\n                }\n            }\n\n            if (notFloating)\n            {\n                EndFetchPRG(Observe, data);\n            }\n            return;\n        }\n        public override byte FetchCHR(ushort Address, bool Observe)\n        {\n            return Cart.CHRRAM[Address];\n        }\n\n        public override void StorePRG(ushort Address, byte Input)\n        {\n            if (Address >= 0x6000 && Address < 0xE000)\n            {\n                Cart.PRGRAM[Address-0x6000] = Input;\n                return;\n            }\n            else if (Address > 0x401F)\n            {\n                ushort tempo = (ushort)(Address & 0x40FF);\n                switch (tempo)\n                {\n                    case 0x4023:\n                        FDS_4023_IOEnable = Input;\n                        if((FDS_4023_IOEnable & 1) == 0)\n                        {\n                            // Disable disk I/O registers\n                            Cart.Emu.IRQ_LevelDetector = false; //acknowledge the IRQ\n                            FDS_4025_Control = 6;\n                        }\n                        return;\n                    case 0x4024:\n                        Cart.FDS.Status_ByteTransferFlag = false;\n                        return;\n                    case 0x4025:\n                        FDS_4025_Control = Input;\n                        return;\n                }\n            }\n        }\n\n        public override void FDS_ByteTransferFlag()\n        {\n            if((FDS_4025_Control & 0x80) != 0)\n            {\n                Cart.Emu.IRQ_LevelDetector = true;\n            }\n        }\n        public override byte FDS_Get4025()\n        {\n            return FDS_4025_Control;\n        }\n\n        public override List<byte> SaveMapperRegisters()\n        {\n            List<byte> State = new List<byte>();\n            foreach (Byte b in Cart.PRGRAM) { State.Add(b); }\n            foreach (Byte b in Cart.CHRRAM) { State.Add(b); }\n\n            State.Add(FDS_4025_Control);\n            State.Add((byte)Cart.FDS.clock);\n            State.Add((byte)(Cart.FDS.clock >> 8));\n            State.Add((byte)Cart.FDS.ShiftRegister);\n            State.Add((byte)Cart.FDS.ShiftRegisterLatch);            \n            State.Add((byte)Cart.FDS.DiskAddress);\n            State.Add((byte)(Cart.FDS.DiskAddress >> 8));\n            State.Add((byte)Cart.FDS.DiskAddressFine);\n            return State;\n        }\n        public override void LoadMapperRegisters(List<byte> State, int startIndex, out int exitIndex)\n        {\n            int p = startIndex;\n            for (int i = 0; i < Cart.PRGRAM.Length; i++) { Cart.PRGRAM[i] = State[p++]; }\n            for (int i = 0; i < Cart.CHRRAM.Length; i++) { Cart.CHRRAM[i] = State[p++]; }\n\n            FDS_4025_Control = State[p++];\n            Cart.FDS.clock = State[p++];\n            Cart.FDS.clock |= (ushort)(State[p++] << 8);\n            Cart.FDS.ShiftRegister = State[p++];\n            Cart.FDS.ShiftRegisterLatch = State[p++];\n            Cart.FDS.DiskAddress = State[p++];\n            Cart.FDS.DiskAddress |= (ushort)(State[p++] << 8);\n            Cart.FDS.DiskAddressFine = State[p++];\n\n            exitIndex = p;\n        }\n\n    }\n}\n"
  },
  {
    "path": "mappers/Mapper_FME7.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace TriCNES.mappers\n{\n    public class Mapper_FME7 : Mapper\n    {\n        // ines Mapper 69\n        public byte Mapper_69_CMD;\n        public byte Mapper_69_CHR_1K0;\n        public byte Mapper_69_CHR_1K1;\n        public byte Mapper_69_CHR_1K2;\n        public byte Mapper_69_CHR_1K3;\n        public byte Mapper_69_CHR_1K4;\n        public byte Mapper_69_CHR_1K5;\n        public byte Mapper_69_CHR_1K6;\n        public byte Mapper_69_CHR_1K7;\n        public byte Mapper_69_Bank_6;\n        public bool Mapper_69_Bank_6_isRAM;\n        public bool Mapper_69_Bank_6_isRAMEnabled;\n        public byte Mapper_69_Bank_8;\n        public byte Mapper_69_Bank_A;\n        public byte Mapper_69_Bank_C;\n        public byte Mapper_69_NametableMirroring; // 0 = Vertical              1 = Horizontal            2 = One Screen Mirroring from $2000 (\"1ScA\")            3 = One Screen Mirroring from $2400 (\"1ScB\")\n        public bool Mapper_69_EnableIRQ;\n        public bool Mapper_69_EnableIRQCounterDecrement;\n        public ushort Mapper_69_IRQCounter; // When enabled the 16-bit IRQ counter is decremented once per CPU cycle. When the IRQ counter is decremented from $0000 to $FFFF an IRQ is generated.\n        public override void FetchPRG(ushort Address, bool Observe)\n        {\n            bool notFloating = false;\n            byte data = 0;\n            if (!Observe) { dataPinsAreNotFloating = false; } else { observedDataPinsAreNotFloating = false; }\n            // Observing can happen on a different thread, so we need to ensure that observing doesn't overwrite the data bus or floating pins status.\n\n            if (Address >= 0x6000)\n            {\n                ushort tempo = (ushort)(Address % 0x2000);\n                if (Address >= 0x6000)\n                {\n                    //actions\n                    if (Address < 0x8000)\n                    {\n                        if (Mapper_69_Bank_6_isRAM)\n                        {\n                            if (Mapper_69_Bank_6_isRAMEnabled)\n                            {\n                                notFloating = true;\n                                data = Cart.PRGRAM[Address & 0x1FFF];\n                            }\n                        }\n                        else\n                        {   //read from ROM\n                            notFloating = true;\n                            data = Cart.PRGROM[(Mapper_69_Bank_6 * 0x2000 + tempo) % Cart.PRGROM.Length];\n                        }\n                    }\n                    else if (Address < 0xA000)\n                    {\n                        notFloating = true;\n                        data = Cart.PRGROM[(Mapper_69_Bank_8 * 0x2000 + tempo) % Cart.PRGROM.Length];\n                    }\n                    else if (Address < 0xC000)\n                    {\n                        notFloating = true;\n                        data = Cart.PRGROM[(Mapper_69_Bank_A * 0x2000 + tempo) % Cart.PRGROM.Length];\n                    }\n                    else if (Address < 0xE000)\n                    {\n                        notFloating = true;\n                        data = Cart.PRGROM[(Mapper_69_Bank_C * 0x2000 + tempo) % Cart.PRGROM.Length];\n                    }\n                    else\n                    {\n                        notFloating = true;\n                        data = Cart.PRGROM[Cart.PRGROM.Length - 0x2000 + tempo];\n                    }\n                }\n            }\n\n            if (notFloating)\n            {\n                EndFetchPRG(Observe, data);\n            }\n            return;\n        }\n        public override void StorePRG(ushort Address, byte Input)\n        {\n            if (Address >= 0x6000)\n            {\n                //actions\n                if (Address < 0x8000)\n                {\n                    if (Mapper_69_Bank_6_isRAM)\n                    {\n                        if (Mapper_69_Bank_6_isRAMEnabled)\n                        {\n                            //writing to RAM\n                            Cart.PRGRAM[Address & 0x1FFF] = Input;\n                        } //else, writing to open bus\n                    } //else it's ROM. writing here does nothing.\n                }\n                else if (Address < 0xA000)\n                {\n                    Mapper_69_CMD = (byte)(Input & 0x0F);\n                }\n                else if (Address < 0xC000)\n                {\n                    switch (Mapper_69_CMD)\n                    {\n                        case 0: Mapper_69_CHR_1K0 = Input; break;\n                        case 1: Mapper_69_CHR_1K1 = Input; break;\n                        case 2: Mapper_69_CHR_1K2 = Input; break;\n                        case 3: Mapper_69_CHR_1K3 = Input; break;\n                        case 4: Mapper_69_CHR_1K4 = Input; break;\n                        case 5: Mapper_69_CHR_1K5 = Input; break;\n                        case 6: Mapper_69_CHR_1K6 = Input; break;\n                        case 7: Mapper_69_CHR_1K7 = Input; break;\n                        case 8: Mapper_69_Bank_6 = (byte)(Input & 0x3F); Mapper_69_Bank_6_isRAM = (Input & 0x40) != 0; Mapper_69_Bank_6_isRAMEnabled = (Input & 0x80) != 0; break;\n                        case 9: Mapper_69_Bank_8 = (byte)(Input & 0x3F); break;\n                        case 10: Mapper_69_Bank_A = (byte)(Input & 0x3F); break;\n                        case 11: Mapper_69_Bank_C = (byte)(Input & 0x3F); break;\n                        case 12: Mapper_69_NametableMirroring = (byte)(Input & 0x3); break;\n                        case 13: Mapper_69_EnableIRQ = (Input & 0x1) != 0; Mapper_69_EnableIRQCounterDecrement = (Input & 0x80) != 0; Cart.Emu.IRQ_LevelDetector = false; break;\n                        case 14: Mapper_69_IRQCounter = (ushort)((Mapper_69_IRQCounter & 0xFF00) | Input); break;\n                        case 15: Mapper_69_IRQCounter = (ushort)((Mapper_69_IRQCounter & 0xFF) | (Input << 8)); break;\n                    }\n                } // else do nothing\n            }\n        }\n        public override byte FetchCHR(ushort Address, bool Observe)\n        {\n            if (Address < 0x400) { return Cart.CHRROM[(Mapper_69_CHR_1K0 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }\n            else if (Address < 0x800) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_69_CHR_1K1 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }\n            else if (Address < 0xC00) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_69_CHR_1K2 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }\n            else if (Address < 0x1000) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_69_CHR_1K3 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }\n            else if (Address < 0x1400) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_69_CHR_1K4 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }\n            else if (Address < 0x1800) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_69_CHR_1K5 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }\n            else if (Address < 0x1C00) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_69_CHR_1K6 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }\n            else { Address &= 0x3FF; return Cart.CHRROM[(Mapper_69_CHR_1K7 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }\n        }\n        public override ushort MirrorNametable(ushort Address)\n        {\n            switch (Mapper_69_NametableMirroring)\n            {\n                case 0: //vertical\n                    Address &= 0x37FF; // mask away $0800\n                    break;\n                case 1: //horizontal\n                    Address = (ushort)((Address & 0x33FF) | ((Address & 0x0800) >> 1)); // mask away $0C00, bit 10 becomes the former bit 11\n                    break;\n                case 2: //one-screen A\n                    Address &= 0x33FF;\n                    break;\n                case 3: //one-screen B\n                    Address &= 0x33FF;\n                    Address |= 0x400;\n                    break;\n            }\n            return Address;\n        }\n        public override List<byte> SaveMapperRegisters()\n        {\n            List<byte> State = new List<byte>();\n            foreach (Byte b in Cart.PRGRAM) { State.Add(b); }\n            foreach (Byte b in Cart.CHRRAM) { State.Add(b); }\n            State.Add(Mapper_69_CMD);\n            State.Add(Mapper_69_CHR_1K0);\n            State.Add(Mapper_69_CHR_1K1);\n            State.Add(Mapper_69_CHR_1K2);\n            State.Add(Mapper_69_CHR_1K3);\n            State.Add(Mapper_69_CHR_1K4);\n            State.Add(Mapper_69_CHR_1K5);\n            State.Add(Mapper_69_CHR_1K6);\n            State.Add(Mapper_69_CHR_1K7);\n            State.Add(Mapper_69_Bank_6);\n            State.Add((byte)(Mapper_69_Bank_6_isRAM ? 1 : 0));\n            State.Add((byte)(Mapper_69_Bank_6_isRAMEnabled ? 1 : 0));\n            State.Add(Mapper_69_Bank_8);\n            State.Add(Mapper_69_Bank_A);\n            State.Add(Mapper_69_Bank_C);\n            State.Add(Mapper_69_NametableMirroring);\n            State.Add((byte)(Mapper_69_EnableIRQ ? 1 : 0));\n            State.Add((byte)(Mapper_69_EnableIRQCounterDecrement ? 1 : 0));\n            State.Add((byte)Mapper_69_IRQCounter);\n            State.Add((byte)(Mapper_69_IRQCounter >> 8));\n            return State;\n        }\n        public override void LoadMapperRegisters(List<byte> State, int startIndex, out int exitIndex)\n        {\n            int p = startIndex;\n            for (int i = 0; i < Cart.PRGRAM.Length; i++) { Cart.PRGRAM[i] = State[p++]; }\n            for (int i = 0; i < Cart.CHRRAM.Length; i++) { Cart.CHRRAM[i] = State[p++]; }\n            Mapper_69_CMD = State[p++];\n            Mapper_69_CHR_1K0 = State[p++];\n            Mapper_69_CHR_1K1 = State[p++];\n            Mapper_69_CHR_1K2 = State[p++];\n            Mapper_69_CHR_1K3 = State[p++];\n            Mapper_69_CHR_1K4 = State[p++];\n            Mapper_69_CHR_1K5 = State[p++];\n            Mapper_69_CHR_1K6 = State[p++];\n            Mapper_69_CHR_1K7 = State[p++];\n            Mapper_69_Bank_6 = State[p++];\n            Mapper_69_Bank_6_isRAM = (State[p++] & 1) == 1;\n            Mapper_69_Bank_6_isRAMEnabled = (State[p++] & 1) == 1;\n            Mapper_69_Bank_8 = State[p++];\n            Mapper_69_Bank_A = State[p++];\n            Mapper_69_Bank_C = State[p++];\n            Mapper_69_NametableMirroring = State[p++];\n            Mapper_69_EnableIRQ = (State[p++] & 1) == 1;\n            Mapper_69_EnableIRQCounterDecrement = (State[p++] & 1) == 1;\n            Mapper_69_IRQCounter = State[p++];\n            Mapper_69_IRQCounter |= (ushort)(State[p++] << 8); \n            exitIndex = p;\n        }\n        public override void CPUClock()\n        {\n            // The sunsoft FME-7 mapper chip has an IRQ counter that ticks down once per CPU cycle.\n            if (Mapper_69_EnableIRQCounterDecrement)\n            {\n                ushort temp = Mapper_69_IRQCounter;\n                Mapper_69_IRQCounter--;\n                if (Mapper_69_EnableIRQ && temp < Mapper_69_IRQCounter)\n                {\n                    Cart.Emu.IRQ_LevelDetector = true;\n                }\n            }\n        }\n\n    }\n}"
  },
  {
    "path": "mappers/Mapper_MMC1.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace TriCNES.mappers\n{\n    public class Mapper_MMC1 : Mapper\n    {\n        // ines Mapper 1\n        public byte Mapper_1_ShiftRegister;\n        public byte Mapper_1_Control = 0x0C;    //0x8000\n        public byte Mapper_1_CHR0;              //0xA000\n        public byte Mapper_1_CHR1;              //0xC000\n        public byte Mapper_1_PRG;               //0xE000\n        public bool Mapper_1_PB;\n        public override void FetchPRG(ushort Address, bool Observe)\n        {\n            bool notFloating = false;\n            byte data = 0;\n            if (!Observe) { dataPinsAreNotFloating = false; } else { observedDataPinsAreNotFloating = false; }\n            // Observing can happen on a different thread, so we need to ensure that observing doesn't overwrite the data bus or floating pins status.\n\n            if (Address >= 0x8000)\n            {\n                notFloating = true;\n                // The bank mode for MMC1:\n                byte MMC1PRGROMBankMode = (byte)((Mapper_1_Control & 0b01100) >> 2);\n                switch (MMC1PRGROMBankMode)\n                {\n                    case 0:\n                    case 1:\n                        {\n                            // switch 32 KB at $8000, ignoring low bit of bank number\n                            ushort tempo = (ushort)(Address & 0x7FFF);\n                            data = Cart.PRGROM[(0x8000 * (Mapper_1_PRG & 0x0E) + tempo) % Cart.PRGROM.Length];\n                        }\n                        break;\n                    case 2:\n                        // fix first bank at $8000 and switch 16 KB bank at $C000\n                        if (Address >= 0xC000)\n                        {\n                            ushort tempo = (ushort)(Address & 0x3FFF);\n                            data = Cart.PRGROM[0x4000 * (Mapper_1_PRG) + tempo];\n                        }\n                        else\n                        {\n                            ushort tempo = (ushort)(Address & 0x3FFF);\n                            data = Cart.PRGROM[tempo];\n                        }\n                        break;\n                    case 3:\n                        // fix last bank at $C000 and switch 16 KB bank at $8000\n                        if (Address >= 0xC000)\n                        {\n                            ushort tempo = (ushort)(Address & 0x3FFF);\n                            data = Cart.PRGROM[Cart.PRGROM.Length - 0x4000 + tempo];\n                        }\n                        else\n                        {\n                            ushort tempo = (ushort)(Address & 0x3FFF);\n                            data = Cart.PRGROM[(0x4000 * (Mapper_1_PRG & 0x0F) + tempo) & (Cart.PRGROM.Length - 1)];\n                        }\n                        break;\n                }\n            }\n            else // if the address is < $8000\n            {\n                if (((Mapper_1_PRG & 0x10) == 0) && Address >= 0x6000) // if Work RAM is enabled\n                {\n                    data = Cart.PRGRAM[Address & 0x1FFF];\n                    notFloating = true;\n                }\n                // else, open bus.\n            }\n            //open bus\n\n            if (notFloating)\n            {\n                EndFetchPRG(Observe, data);\n            }\n            return;\n        }\n        public override void StorePRG(ushort Address, byte Input)\n        {\n            if (Address < 0x8000) //WRAM not available on MMC1A\n            {\n                if (((Mapper_1_PRG & 0x10) == 0) /*&& Mapper != 1*/)\n                {\n                    //Battery backed RAM\n                    Cart.PRGRAM[Address & 0x1FFF] = Input;\n                    return;\n                }\n                else\n                {\n                    return; //do nothing\n                }\n            }\n            else\n            {   // shift the shirftRegister and add the new bit\n                Mapper_1_PB = (Mapper_1_ShiftRegister & 1) == 1;\n                Mapper_1_ShiftRegister >>= 1;\n                Mapper_1_ShiftRegister |= (byte)((Input & 1) << 4);\n            }\n            if (Mapper_1_PB) // if the '1' that was initialized in bit 4 is shifted into the bus\n            {\n                // copy shift register to the desired internal register.\n                switch (Address & 0xE000)\n                {\n                    case 0x8000: //control\n                        Mapper_1_Control = Mapper_1_ShiftRegister;\n                        break;\n                    case 0xA000: //CHR0\n                        Mapper_1_CHR0 = Mapper_1_ShiftRegister;\n                        break;\n                    case 0xC000: //CHR1\n                        Mapper_1_CHR1 = Mapper_1_ShiftRegister;\n                        break;\n                    case 0xE000: //PRG\n                        Mapper_1_PRG = Mapper_1_ShiftRegister;\n                        break;\n                }\n                Mapper_1_ShiftRegister = 0b10000;\n            }\n            if ((Input & 0b10000000) != 0)\n            {\n                Mapper_1_ShiftRegister = 0b10000;\n                Mapper_1_Control |= 0b01100;\n            }\n        }\n        public override byte FetchCHR(ushort Address, bool Observe)\n        {\n            // bit 4 of Mapper_1_Control controls how the pattern tables are swapped. if set, 2 banks of 4Kib. Otherwise, 1 8Kib bank\n            if ((Mapper_1_Control & 0x10) != 0)\n            {\n                // with the MMC1 chip, you can swap out the pattern tables.\n                // address < 0x1000 is the first pattern table, else, the second pattern table.\n                // if the final write for the MMC1 shift register was in the $A000 - $BFFF, this updates Mapper_1_CHR0\n                // if the final write for the MMC1 shift register was in the $B000 - $CFFF, this updates Mapper_1_CHR1\n                if (Address < 0x1000) { return Cart.CHRROM[((Mapper_1_CHR0 & 0x1F) * 0x1000 + Address) & (Cart.CHRROM.Length - 1)]; }\n                else { Address &= 0xFFF; return Cart.CHRROM[((Mapper_1_CHR1 & 0x1F) * 0x1000 + Address) & (Cart.CHRROM.Length - 1)]; }\n            }\n            else // one swappable bank that changes both pattern tables.\n            {\n                // this uses the value written to Mapper_1_CHR0\n                return Cart.CHRROM[((Mapper_1_CHR0 & 0b11111110) * 0x2000 + Address) & (Cart.CHRROM.Length - 1)];\n            }\n        }\n        public override ushort MirrorNametable(ushort Address)\n        {\n            switch (Mapper_1_Control & 3)\n            {\n                case 0: //one screen, low\n                    Address &= 0x33FF;\n                    break;\n                case 1: //one screen, high\n                    Address &= 0x33FF;\n                    Address |= 0x400;\n                    break;\n                case 2: //vertical\n                    Address &= 0x37FF; // mask away $0800\n                    break;\n                case 3: //horizontal\n                    Address = (ushort)((Address & 0x33FF) | ((Address & 0x0800) >> 1)); // mask away $0C00, bit 10 becomes the former bit 11\n\n                    break;\n            }\n            return Address;\n        }\n        public override List<byte> SaveMapperRegisters()\n        {\n            List<byte> State = new List<byte>();\n            foreach (Byte b in Cart.PRGRAM) { State.Add(b); }\n            foreach (Byte b in Cart.CHRRAM) { State.Add(b); }\n            State.Add(Mapper_1_ShiftRegister);\n            State.Add(Mapper_1_Control);\n            State.Add(Mapper_1_CHR0);\n            State.Add(Mapper_1_CHR1);\n            State.Add(Mapper_1_ShiftRegister);\n            State.Add((byte)(Mapper_1_PB ? 1 : 0));\n            return State;\n        }\n        public override void LoadMapperRegisters(List<byte> State, int startIndex, out int exitIndex)\n        {\n            int p = startIndex;\n            for (int i = 0; i < Cart.PRGRAM.Length; i++) { Cart.PRGRAM[i] = State[p++]; }\n            for (int i = 0; i < Cart.CHRRAM.Length; i++) { Cart.CHRRAM[i] = State[p++]; }\n            Mapper_1_ShiftRegister = State[p++];\n            Mapper_1_Control = State[p++];\n            Mapper_1_CHR0 = State[p++];\n            Mapper_1_CHR1 = State[p++];\n            Mapper_1_ShiftRegister = State[p++];\n            Mapper_1_PB = (State[p++] & 1) == 1;\n            exitIndex = p;\n        }\n    }\n}\n"
  },
  {
    "path": "mappers/Mapper_MMC2.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace TriCNES.mappers\n{\n    public class Mapper_MMC2 : Mapper\n    {\n        // ines Mapper 9\n        public byte Mapper_9_BankSelect;\n        public byte Mapper_9_CHR0_FD;\n        public byte Mapper_9_CHR0_FE;\n        public byte Mapper_9_CHR1_FD;\n        public byte Mapper_9_CHR1_FE;\n        public bool Mapper_9_NametableMirroring;\n        public bool Mapper_9_Latch0_FE;\n        public bool Mapper_9_Latch1_FE; \n        public override void FetchPRG(ushort Address, bool Observe)\n        {\n            bool notFloating = false;\n            byte data = 0;\n            if (!Observe) { dataPinsAreNotFloating = false; } else { observedDataPinsAreNotFloating = false; }\n            // Observing can happen on a different thread, so we need to ensure that observing doesn't overwrite the data bus or floating pins status.\n\n            if (Address >= 0xA000)\n            {\n                notFloating = true;\n                data = Cart.PRGROM[((Cart.PRG_Size - 2) << 14) | (Address & 0x7FFF)];\n            }\n            else if(Address >= 0x8000)\n            {\n                notFloating = true;\n                data = Cart.PRGROM[(Mapper_9_BankSelect << 13) | (Address & 0x1FFF)];\n            }\n\n            if (notFloating)\n            {\n                EndFetchPRG(Observe, data);\n            }\n            return;\n        }\n        public override void StorePRG(ushort Address, byte Input)\n        {\n            if (Address < 0xA000)\n            {\n                // nothing\n            }\n            else if (Address < 0xB000) // PRG Bank select\n            {\n                Mapper_9_BankSelect = (byte)(Input & 0x0F);\n            }\n            else if (Address < 0xC000) // CHR0 Bank select\n            {\n                Mapper_9_CHR0_FD = (byte)(Input & 0x1F);\n            }\n            else if (Address < 0xD000) // CHR0 Bank select\n            {\n                Mapper_9_CHR0_FE = (byte)(Input & 0x1F);\n            }\n            else if (Address < 0xE000) // CHR1 Bank select\n            {\n                Mapper_9_CHR1_FD = (byte)(Input & 0x1F);\n            }\n            else if (Address < 0xF000) // CHR1 Bank select\n            {\n                Mapper_9_CHR1_FE = (byte)(Input & 0x1F);\n            }\n            else // Nametable mirroring\n            {\n                Mapper_9_NametableMirroring = (Input & 0x1) == 1;\n            }\n        }\n        public override byte FetchCHR(ushort Address, bool Observe)\n        {\n            byte temp = 0;\n            ushort Addr = Address;\n            if (Address < 0x1000) { temp = Cart.CHRROM[(Mapper_9_Latch0_FE ? Mapper_9_CHR0_FE : Mapper_9_CHR0_FD) * 0x1000 + Addr]; }\n            else { Addr &= 0xFFF; temp = Cart.CHRROM[(Mapper_9_Latch1_FE ? Mapper_9_CHR1_FE : Mapper_9_CHR1_FD) * 0x1000 + Addr]; }\n            if (!Observe)\n            {\n                if (Address == 0x0FD8)\n                {\n                    Mapper_9_Latch0_FE = false;\n                }\n                else if (Address == 0x0FE8)\n                {\n                    Mapper_9_Latch0_FE = true;\n                }\n                else if (Address >= 0x1FD8 && Address <= 0x1FDF)\n                {\n                    Mapper_9_Latch1_FE = false;\n                }\n                else if (Address >= 0x1FE8 && Address <= 0x1FEF)\n                {\n                    Mapper_9_Latch1_FE = true;\n                }\n            }\n            return temp;\n        }\n        public override ushort MirrorNametable(ushort Address)\n        {\n            if (Mapper_9_NametableMirroring) //horizontal\n            {\n                Address = (ushort)((Address & 0x33FF) | ((Address & 0x0800) >> 1)); // mask away $0C00, bit 10 becomes the former bit 11\n            }\n            else //vertical\n            {\n                Address &= 0x37FF; // mask away $0800\n            }\n            return Address;\n        }\n        public override List<byte> SaveMapperRegisters()\n        {\n            List<byte> State = new List<byte>();\n            foreach (Byte b in Cart.PRGRAM) { State.Add(b); }\n            foreach (Byte b in Cart.CHRRAM) { State.Add(b); }\n            State.Add(Mapper_9_BankSelect);\n            State.Add(Mapper_9_CHR0_FD);\n            State.Add(Mapper_9_CHR0_FE);\n            State.Add(Mapper_9_CHR1_FD);\n            State.Add(Mapper_9_CHR1_FE);\n            State.Add((byte)(Mapper_9_NametableMirroring ? 1 : 0));\n            State.Add((byte)(Mapper_9_Latch0_FE ? 1 : 0));\n            State.Add((byte)(Mapper_9_Latch1_FE ? 1 : 0)); return State;\n        }\n        public override void LoadMapperRegisters(List<byte> State, int startIndex, out int exitIndex)\n        {\n            int p = startIndex;\n            for (int i = 0; i < Cart.PRGRAM.Length; i++) { Cart.PRGRAM[i] = State[p++]; }\n            for (int i = 0; i < Cart.CHRRAM.Length; i++) { Cart.CHRRAM[i] = State[p++]; }\n            Mapper_9_BankSelect = State[p++];\n            Mapper_9_CHR0_FD = State[p++];\n            Mapper_9_CHR0_FE = State[p++];\n            Mapper_9_CHR1_FD = State[p++];\n            Mapper_9_CHR1_FE = State[p++];\n            Mapper_9_NametableMirroring = (State[p++] & 1) == 1;\n            Mapper_9_Latch0_FE = (State[p++] & 1) == 1;\n            Mapper_9_Latch1_FE = (State[p++] & 1) == 1;\n            exitIndex = p;\n        }\n    }\n}"
  },
  {
    "path": "mappers/Mapper_MMC3.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace TriCNES.mappers\n{\n    public class Mapper_MMC3 : Mapper\n    {\n        // ines Mapper 4\n        public byte Mapper_4_8000;      // The value written to $8000 (or any even address between $8000 and $9FFE)\n        public byte Mapper_4_BankA;     // The PRG bank between $A000 and $BFFF\n        public byte Mapper_4_Bank8C;    // The PRG bank that could either be at $8000 through 9FFF, or $C000 through $DFFF\n        public byte Mapper_4_CHR_2K0;\n        public byte Mapper_4_CHR_2K8;\n        public byte Mapper_4_CHR_1K0;\n        public byte Mapper_4_CHR_1K4;\n        public byte Mapper_4_CHR_1K8;\n        public byte Mapper_4_CHR_1KC;\n        public byte Mapper_4_IRQLatch;\n        public byte Mapper_4_IRQCounter;\n        public bool Mapper_4_EnableIRQ;\n        public bool Mapper_4_ReloadIRQCounter;\n        public bool Mapper_4_NametableMirroring; // MMC3 has it's own way of controlling how the nametables are mirrored.\n        public byte Mapper_4_PRGRAMProtect;\n        public byte Mapper_4_M2Filter;\n        public override void FetchPRG(ushort Address, bool Observe)\n        {\n            bool notFloating = false;\n            byte data = 0;\n            if (!Observe) { dataPinsAreNotFloating = false; } else { observedDataPinsAreNotFloating = false; }\n            // Observing can happen on a different thread, so we need to ensure that observing doesn't overwrite the data bus or floating pins status.\n\n            if (Address >= 0xE000) // This bank is fixed the the final PRG bank of the ROM\n            {\n                notFloating = true;\n                data = Cart.PRGROM[(Cart.PRG_SizeMinus1 << 14) | (Address & 0x3FFF)];\n            }\n            else if (Address >= 0xC000)\n            {\n                notFloating = true;\n                if ((Mapper_4_8000 & 0x40) == 0x40)\n                {\n                    //$C000 swappable\n                    data = Cart.PRGROM[(Mapper_4_Bank8C << 13) | (Address & 0x1FFF)];\n                }\n                else\n                {\n                    //$8000 swappable\n                    data = Cart.PRGROM[(Cart.PRG_SizeMinus1 << 14) | (Address & 0x1FFF)];\n                }\n            }\n            else if (Address >= 0xA000)\n            {\n                notFloating = true;\n                //$8000 swappable\n                data = Cart.PRGROM[(Mapper_4_BankA << 13) | (Address & 0x1FFF)];\n            }\n            else if (Address >= 0x8000)\n            {\n                notFloating = true;\n                if ((Mapper_4_8000 & 0x40) == 0x40)\n                {\n                    //$8000 swappable\n                    data = Cart.PRGROM[(Cart.PRG_SizeMinus1 << 14) | (Address & 0x1FFF)];\n                }\n                else\n                {\n                    //$C000 swappable\n                    data = Cart.PRGROM[(Mapper_4_Bank8C << 13) | (Address & 0x1FFF)];\n                }\n            }\n            else if (Address >= 0x6000)\n            {\n                if (Cart.SubMapper == 1) // MMC6\n                {\n                    if ((Mapper_4_8000 & 0x20) != 0)\n                    {\n                        // MMC6 differs from MMC3 since there's only 1Kib of PRG RAM\n                        if (Address >= 0x7000 && Address <= 0x71FF)\n                        {\n                            if ((Mapper_4_PRGRAMProtect & 0x20) != 0)\n                            {\n                                notFloating = true;\n                                data = Cart.PRGRAM[Address & 0x3FF];\n                            }\n                        }\n                        else if (Address >= 0x7200 && Address <= 0x73FF)\n                        {\n                            if ((Mapper_4_PRGRAMProtect & 0x80) != 0)\n                            {\n                                notFloating = true;\n                                data = Cart.PRGRAM[Address & 0x3FF];\n                            }\n                        }\n                    }\n                }\n                else\n                {\n                    if ((Mapper_4_PRGRAMProtect & 0x80) != 0)\n                    {\n                        notFloating = true;\n                        data = Cart.PRGRAM[Address & 0x1FFF];\n                    }\n                }\n            }\n            //else, open bus\n\n            if (notFloating)\n            {\n                EndFetchPRG(Observe, data);\n            }\n            return;\n        }\n        public override void StorePRG(ushort Address, byte Input)\n        {\n            if (Address < 0x8000)\n            {   //Battery backed RAM\n\n                if (Cart.SubMapper == 1) // MMC6\n                {\n                    // MMC6 differs from MMC3 since there's only 1Kib of PRG RAM\n                    if ((Mapper_4_8000 & 0x20) != 0)\n                    {\n                        if (Address >= 0x7000 && Address <= 0x71FF)\n                        {\n                            if ((Mapper_4_PRGRAMProtect & 0x10) != 0)\n                            {\n                                Cart.PRGRAM[Address & 0x3FF] = Input;\n\n                            }\n                        }\n                        else if (Address >= 0x7200 && Address <= 0x73FF)\n                        {\n                            if ((Mapper_4_PRGRAMProtect & 0x40) != 0)\n                            {\n                                Cart.PRGRAM[Address & 0x3FF] = Input;\n                            }\n                        }\n                    }\n                }\n                else if ((Mapper_4_PRGRAMProtect & 0xC0) != 0) // bit 7 enables PRG RAM, bit 6 enables writing there.\n                {\n                    Cart.PRGRAM[Address & 0x1FFF] = Input;\n                }\n                return;\n            }\n            else\n            {\n                ushort tempo = (ushort)(Address & 0xE001);\n                switch (tempo)\n                {\n                    case 0x8000:\n                        Mapper_4_8000 = Input;\n                        return;\n                    case 0x8001:\n                        byte mode = (byte)(Mapper_4_8000 & 7);\n                        switch (mode)\n                        {\n                            case 0: //PPU ($0000 - $07FF) ?+ $1000\n                                Mapper_4_CHR_2K0 = (byte)(Input & 0xFE);\n                                return;\n                            case 1: //PPU ($0800 - $0FFF) ?+ $1000\n                                Mapper_4_CHR_2K8 = (byte)(Input & 0xFE);\n                                return;\n                            case 2: //PPU ($1000 - $13FF) ?- $1000\n                                Mapper_4_CHR_1K0 = Input;\n                                return;\n                            case 3: //PPU ($1400 - $17FF) ?- $1000\n                                Mapper_4_CHR_1K4 = Input;\n                                return;\n                            case 4: //PPU ($1800 - $1BFF) ?- $1000\n                                Mapper_4_CHR_1K8 = Input;\n                                return;\n                            case 5: //PPU ($1C00 - $1FFF) ?- $1000\n                                Mapper_4_CHR_1KC = Input;\n                                return;\n                            case 6: //PRG ($8000 - $9FFF) ?+ 0x4000\n                                Mapper_4_Bank8C = (byte)(Input & (Cart.PRG_Size * 2 - 1));\n                                return;\n                            case 7: //PRG ($A000 - $BFFF)\n                                Mapper_4_BankA = (byte)(Input & (Cart.PRG_Size * 2 - 1));\n                                return;\n                        }\n                        return;\n                    case 0xA000:\n                        Mapper_4_NametableMirroring = (Input & 1) == 1;\n                        return;\n                    case 0xA001:\n                        Mapper_4_PRGRAMProtect = Input;\n                        return;\n                    case 0xC000:\n                        Mapper_4_IRQLatch = Input;\n                        return;\n                    case 0xC001:\n                        Mapper_4_IRQCounter = 0xFF;\n                        Mapper_4_ReloadIRQCounter = true;\n                        return;\n                    case 0xE000:\n                        Mapper_4_EnableIRQ = false;\n                        Cart.Emu.IRQ_LevelDetector = false;\n                        return;\n                    case 0xE001:\n                        Mapper_4_EnableIRQ = true;\n                        return;\n                }\n            }\n        }\n        public override byte FetchCHR(ushort Address, bool Observe)\n        {\n            //Writes to $8000 determine the mode, writes to $8001 determine the banks\n            if ((Mapper_4_8000 & 0x80) == 0) // bit 7 of the previous write to $8000 determines which pattern table is 2 2kb banks, and which is 4 1kb banks.\n            {\n                if (Address < 0x800) { return Cart.CHRROM[(Mapper_4_CHR_2K0 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }\n                else if (Address < 0x1000) { Address &= 0x7FF; return Cart.CHRROM[(Mapper_4_CHR_2K8 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }\n                else if (Address < 0x1400) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_4_CHR_1K0 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }\n                else if (Address < 0x1800) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_4_CHR_1K4 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }\n                else if (Address < 0x1C00) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_4_CHR_1K8 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }\n                else { Address &= 0x3FF; return Cart.CHRROM[(Mapper_4_CHR_1KC * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }\n            }\n            else\n            {\n                if (Address < 0x400) { return Cart.CHRROM[(Mapper_4_CHR_1K0 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }\n                else if (Address < 0x800) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_4_CHR_1K4 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }\n                else if (Address < 0xC00) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_4_CHR_1K8 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }\n                else if (Address < 0x1000) { Address &= 0x3FF; return Cart.CHRROM[(Mapper_4_CHR_1KC * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }\n                else if (Address < 0x1800) { Address &= 0x7FF; return Cart.CHRROM[(Mapper_4_CHR_2K0 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }\n                else { Address &= 0x7FF; return Cart.CHRROM[(Mapper_4_CHR_2K8 * 0x400 + Address) & (Cart.CHRROM.Length - 1)]; }\n            }\n        }\n        public override byte FetchPPU()\n        {\n            // This will always use the upper 8 bits of the address bus | the octal latch. This replaces the lower 8 bits of the address bus.\n            ushort Address = (ushort)((Cart.Emu.PPU_AddressBus & 0x3F00) | Cart.Emu.PPU_OctalLatch);\n            bool CIRAM = Address >= 0x2000;\n            if (!CIRAM)\n            {\n                if (Cart.UsingCHRRAM)\n                {\n                    Cart.Emu.PPU_AddressBus &= 0xFF00;\n                    Cart.Emu.PPU_AddressBus |= Cart.CHRRAM[Address];\n                }\n                else\n                {\n                    //Pattern Table\n                    Cart.Emu.PPU_AddressBus &= 0xFF00;\n                    Cart.Emu.PPU_AddressBus |= Cart.MapperChip.FetchCHR(Address, false);\n                }\n            }\n            else // if the VRAM address is >= $2000, we need to consider nametable mirroring.\n            {\n                Address = MirrorNametable(Address);\n\n                if (Cart.AlternativeNametableArrangement)\n                {\n\n                    if ((Address & 0x800) != 0)\n                    {\n                        // using the extra PRG VRAM.\n                        Address &= 0x7FF;\n                        Cart.Emu.PPU_AddressBus &= 0xFF00;\n                        Cart.Emu.PPU_AddressBus |= Cart.PRGVRAM[Address];\n                    }\n                    else\n                    {\n                        Address &= 0x7FF;\n                        Cart.Emu.PPU_AddressBus &= 0xFF00;\n                        Cart.Emu.PPU_AddressBus |= Cart.Emu.VRAM[Address];\n                    }\n                }\n                else\n                {\n                    Address &= 0x7FF;\n                    Cart.Emu.PPU_AddressBus &= 0xFF00;\n                    Cart.Emu.PPU_AddressBus |= Cart.Emu.VRAM[Address];\n                }\n            }\n            return (byte)Cart.Emu.PPU_AddressBus;\n        }\n        public override ushort MirrorNametable(ushort Address)\n        {\n            if (!Cart.AlternativeNametableArrangement)\n            {\n                if (Mapper_4_NametableMirroring) //horizontal\n                {\n                    return (ushort)((Address & 0x33FF) | ((Address & 0x0800) >> 1)); // mask away $0C00, bit 10 becomes the former bit 11\n                }\n                else //vertical\n                {\n                    return (ushort)(Address & 0x37FF); // mask away $0800\n                }\n            }\n            return Address;\n        }\n        public override List<byte> SaveMapperRegisters()\n        {\n            List<byte> State = new List<byte>();\n            foreach (Byte b in Cart.PRGRAM) { State.Add(b); }\n            foreach (Byte b in Cart.CHRRAM) { State.Add(b); }\n            if (Cart.PRGVRAM != null)\n            {\n                foreach (Byte b in Cart.PRGVRAM) { State.Add(b); }\n            }\n            State.Add(Mapper_4_8000);\n            State.Add(Mapper_4_BankA);\n            State.Add(Mapper_4_Bank8C);\n            State.Add(Mapper_4_CHR_2K0);\n            State.Add(Mapper_4_CHR_2K8);\n            State.Add(Mapper_4_CHR_1K0);\n            State.Add(Mapper_4_CHR_1K4);\n            State.Add(Mapper_4_CHR_1K8);\n            State.Add(Mapper_4_CHR_1KC);\n            State.Add(Mapper_4_IRQLatch);\n            State.Add(Mapper_4_IRQCounter);\n            State.Add((byte)(Mapper_4_EnableIRQ ? 1 : 0));\n            State.Add((byte)(Mapper_4_ReloadIRQCounter ? 1 : 0));\n            State.Add((byte)(Mapper_4_NametableMirroring ? 1 : 0));\n            State.Add(Mapper_4_PRGRAMProtect);\n            State.Add(Mapper_4_M2Filter);\n            return State;\n        }\n        public override void LoadMapperRegisters(List<byte> State, int startIndex, out int exitIndex)\n        {\n            int p = startIndex;\n            for (int i = 0; i < Cart.PRGRAM.Length; i++) { Cart.PRGRAM[i] = State[p++]; }\n            for (int i = 0; i < Cart.CHRRAM.Length; i++) { Cart.CHRRAM[i] = State[p++]; }\n            if (Cart.PRGVRAM != null)\n            {\n                for (int i = 0; i < Cart.PRGVRAM.Length; i++) { Cart.PRGVRAM[i] = State[p++]; }\n            }\n            Mapper_4_8000 = State[p++];\n            Mapper_4_BankA = State[p++];\n            Mapper_4_Bank8C = State[p++];\n            Mapper_4_CHR_2K0 = State[p++];\n            Mapper_4_CHR_2K8 = State[p++];\n            Mapper_4_CHR_1K0 = State[p++];\n            Mapper_4_CHR_1K4 = State[p++];\n            Mapper_4_CHR_1K8 = State[p++];\n            Mapper_4_CHR_1KC = State[p++];\n            Mapper_4_IRQLatch = State[p++];\n            Mapper_4_IRQCounter = State[p++];\n            Mapper_4_EnableIRQ = (State[p++] & 1) == 1;\n            Mapper_4_ReloadIRQCounter = (State[p++] & 1) == 1;\n            Mapper_4_NametableMirroring = (State[p++] & 1) == 1;\n            Mapper_4_PRGRAMProtect = State[p++];\n            Mapper_4_M2Filter = State[p++];\n            exitIndex = p;\n        }\n\n        public override void PPUClock()\n        {\n            // if bit 12 of the ppu address bus (A12) changes:\n            if (!Cart.Emu.PPU_A12_Prev && ((Cart.Emu.PPU_AddressBus & 0b0001000000000000) != 0) && Mapper_4_M2Filter == 3)\n            {\n                if (Mapper_4_ReloadIRQCounter)\n                {\n                    // If we're reloading the IRQ counter\n                    Mapper_4_IRQCounter = Mapper_4_IRQLatch; // The latch is the reset value.\n                    Mapper_4_ReloadIRQCounter = false;\n                    if (Mapper_4_IRQCounter == 0)  // if the latch is set to 0, you need to enable the IRQ.\n                    {\n                        if (Mapper_4_EnableIRQ) // if setting the value to zero, run an IRQ\n                        {\n                            Cart.Emu.IRQ_LevelDetector = true;\n                        }\n                    }\n                }\n                else\n                {\n                    // decrement the counter\n                    Mapper_4_IRQCounter--;\n                    if (Mapper_4_IRQCounter == 0) // if decrementing the counter moved it to 0...\n                    {\n                        if (Mapper_4_EnableIRQ) // and the MMC3 IRQ is enabled...\n                        {\n                            Cart.Emu.IRQ_LevelDetector = true; // Run an IRQ!\n                        }\n                    }\n                    else if (Mapper_4_IRQCounter == 255) // if the counter underflows...\n                    {\n                        Mapper_4_IRQCounter = Mapper_4_IRQLatch; // reset the irq counter\n                        if (Mapper_4_IRQCounter == 0)  // if the latch is set to 0, you need to enable the IRQ... again\n                        {\n                            if (Mapper_4_EnableIRQ)\n                            {\n                                Cart.Emu.IRQ_LevelDetector = true;\n                            }\n                        }\n                    }\n\n                }\n            }\n            if ((Cart.Emu.PPU_AddressBus & 0b0001000000000000) != 0)\n            {\n                Mapper_4_M2Filter = 0;\n            }\n        }\n        public override void CPUClockRise()\n        {\n            if ((Cart.Emu.PPU_AddressBus & 0b0001000000000000) == 0)\n            {\n                if (Mapper_4_M2Filter < 3)\n                {\n                    Mapper_4_M2Filter++;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "mappers/Mapper_NROM.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace TriCNES.mappers\n{\n    public class Mapper_NROM : Mapper\n    {\n        // ines Mapper 0\n    }\n}\n"
  },
  {
    "path": "mappers/Mapper_NULL.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace TriCNES.mappers\n{\n    public class Mapper_NULL : Mapper\n    {\n        // There is not a cartridge inserted in the console.\n\n        public override void FetchPRG(ushort Address, bool Observe)\n        {\n            dataPinsAreNotFloating = false;\n            // the data pins are always floating. There's no cartridge inserted!\n            return;\n        }\n\n        public override byte FetchCHR(ushort Address, bool Observe)\n        {\n            // there's no cartridge. TODO: Look into this. Supposedly this would likely be the lower 8 bits of the address bus, but CIRAM enable is also floating.\n            return 0;\n        }\n        public override ushort MirrorNametable(ushort Address)\n        {\n            return Address;\n        }\n        public override List<byte> SaveMapperRegisters()\n        {\n            List<byte> State = new List<byte>();\n            return State;\n        }\n        public override void LoadMapperRegisters(List<byte> State, int startIndex, out int exitIndex)\n        {\n            int p = startIndex;\n            exitIndex = p;\n        }\n    }\n}\n"
  },
  {
    "path": "mappers/Mapper_UxROM.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace TriCNES.mappers\n{\n    public class Mapper_UxROM : Mapper\n    {\n        // ines Mapper 2\n        public byte Mapper_2_BankSelect;\n        public override void FetchPRG(ushort Address, bool Observe)\n        {\n            bool notFloating = false;\n            byte data = 0;\n            if (!Observe) { dataPinsAreNotFloating = false; } else { observedDataPinsAreNotFloating = false; }\n            // Observing can happen on a different thread, so we need to ensure that observing doesn't overwrite the data bus or floating pins status.\n\n            if (Address >= 0x8000)\n            {\n                notFloating = true;\n                if (Address >= 0xC000)\n                {\n                    ushort tempo = (ushort)(Address & 0x3FFF);\n                    data = Cart.PRGROM[Cart.PRGROM.Length - 0x4000 + tempo];\n                }\n                else\n                {\n                    ushort tempo = (ushort)(Address & 0x3FFF);\n                    data = Cart.PRGROM[0x4000 * (Mapper_2_BankSelect & 0x0F) + tempo];\n                }\n            }\n\n            if (notFloating)\n            {\n                EndFetchPRG(Observe, data);\n            }\n            return;\n        }\n        public override void StorePRG(ushort Address, byte Input)\n        {\n            if (Address >= 0x8000)\n            {\n                Mapper_2_BankSelect = (byte)(Input & 0xF);\n            }\n        }\n        public override List<byte> SaveMapperRegisters()\n        {\n            List<byte> State = new List<byte>();\n            foreach (Byte b in Cart.PRGRAM) { State.Add(b); }\n            foreach (Byte b in Cart.CHRRAM) { State.Add(b); }\n            State.Add(Mapper_2_BankSelect);\n            return State;\n        }\n        public override void LoadMapperRegisters(List<byte> State, int startIndex, out int exitIndex)\n        {\n            int p = startIndex;\n            for (int i = 0; i < Cart.PRGRAM.Length; i++) { Cart.PRGRAM[i] = State[p++]; }\n            for (int i = 0; i < Cart.CHRRAM.Length; i++) { Cart.CHRRAM[i] = State[p++]; }\n            Mapper_2_BankSelect = State[p++];\n            exitIndex = p;\n        }\n    }\n}"
  },
  {
    "path": "packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"ppy.SDL2-CS\" version=\"1.0.82\" targetFramework=\"net48\" />\n</packages>"
  }
]