NOTE: This is not dead. Just on a bit of a hiatus while I wrestle with new fatherhood.
Ostensibly, an Nintendo Entertainment System (NES) emulator with a view to encompassing other systems. Creating a pluggable multi-emulator. In actuality, it is not about getting a working emulator, for a NES or anything else. There are plenty of them out there. It's about taking a complex problem and designing the best abstraction possible. Allowing us to discuss complex ideas in simple language.
Too often I've:
- had to sacrifice good implementation for fast functionality
- dealt with code in which concision hampered readability
- consumed development time in lengthy, bloated builds. Usually caused by complex and brittle system testing
- written under-specified features which need to be re-written over and over
- work with naive domain knowledge due to time pressure
- written solutions to problems I had no time to completely understand.
Any fool can write code that a computer can understand. Good programmers write code that humans can understand. (M. Fowler)
I wanted something I could redesign over and over as my knowledge of the domain grew and as I felt the frustrations of having to reaquaint myself with pirces of code I hadn't seen in a while. Something I could test in a thousand different ways, then tweak and experiment with build processes so that the development cycle is rapid and fluid. That I could tweak the code over and over to make it simpler and simpler to understand.
There are also desirable side effects. I wanted to write my own emulator, play the games of my childhood and know that I wrote the platform that they were running on and becoming even more familiar with the first pieces of software I fell in love with. I wanted a large codebase I had complete control over and could try out tools and technologies. I got to the stage of the latter, quite a while ago and I'm crawling towards the former.
There is a debug UI for the MOS 6502 which provides a basic register and memory overview for running code through step by step in DebuggerWindow.java. Run with the Gradle command runDebugUI
and you'll get an interface that looks something like
On the left you'll see tabs of the first 5 memory pages organised in blocks of 4 with their locations displayed in red on the left. The Program Counter location will be colored green.
In the center we have a choice of two tabs
- Registers: Which display all registers and flags, their names in blue and representations of them as decimal and hexadecimal in red.
- Code: A simple code window which can be used to compile 6502 assembly and load it into page 0 at location 0.
On the bottom we have a reset button which will reset everything to it's initial state and a step button which will issue the next instruction.
At the top we have the currently executing instruction and on the right a history of instructions both consisting of their location, arguments and a short description.
I've seperate (at least) the NES section of this down into 7 stages:
- I blasted through the first phase due to the massive amount of documentation on the MOS 6502
- While researching phase 3, I churned through the relitively basic work of parsing iNES files of phase 2 (without edge cases for now)
- Phase 3 is kinda where I'm stuck at the moment, struggling to find time to consolodate all the documentation and existing on the APU, which is less abundant than of the MOS 6502 and far more messy
- Phase 4 is going to be a decent challenge I think, where I need to start concentrating on timings
- Phase 5 and 6 are bringing it all together into a useable system
So currenly large scale features are undergoing research and early design. This also gives me time to improve and tweak what is there.
The plan was to develop in a TDD (Test Driven Development) centric way, that is via Red-Green testing; i.e. writing failing/red tests that describe functionality then writing that functionality to make the tests pass/green and iteratively writing a complete application.
Technologies that I have used, liked and continued to use as part of the project...
- Trello for work breakdown and project management.
- Java/JUnit for basic functionality tests, adding mocks and more expressive syntax with Mockito. This includes features such as Theories.
- Groovy/Spock for data-driven tests, adding mocks and more expressive syntax with Hamcrest. For covering various variations of class creation and method use in a clear, concise way that JUnit struggles with.
- junit-quickcheck and Spock Genesis for property-based testing in Java and Groovy respectively.
- JUnit Theory Suite for unrolling JUnit Theories. This will unroll all data points combinatorially to a Theory
- TravisCI for continuous integration & build status GitHub Shield, making sure my build always builds and my tests always pass.
- Pitest reports. To allow us to use mutation testing to validate and improve our (Spock & JUnit) unit tests. The Pitest GitHub shield is a self made Python program.
- JaCoCo reports. To allow us to strive for high code coverage. Mainly for the GitHub shield using CodeCov.
- Static analysis done in my development environment on IntelliJ IDEA and online (including GitHub shield) by Codeacy.
Technologies that I have used yet disliked or haven't saw a place for them in my project for whatever reason...
- JParams toStringTester for
toString
testing but it didn't seem to work very well, I filed an issue but the project has since been archived. - JUnit QuickTheories for property based testing but it's much more verbose for no added benefit over junit-quickcheck
- Spockito to give the ability to unroll JUnit Theories like in Spock data-driven tests but I'm not a big fan of the syntax and attaches
@DataPoint
s to the methods. It would be great for adding data-driven tests if you were limited to JUnit, however - Kotlin for testing and various testing frameworks like Spek and kotlintest but it offers nothing I don't already have and property/data-driven/theory testing is pretty ugly and/or weak.
- Beads Project currently investigating for audio synthesis until I have the knowledge to roll my own. The library is so small, focused and nice to use I may just keep it. Unfortunately it's not on any repo so it needs to be manually included.
Java bytes are signed, meaning it's a pain to deal with them. Sometimes we want to deal with raw bytes such as memory read and writes, sometimes we want to have them signed and later in BCD mode.
JaCoCo doesn't report coverage of String
based switch
statements well
- StackOverflow as always has been a huge help, specifically Godin, also a developer of JaCoCo for his help. eg. here & here
- The 6502 Programming Facebook group has been invaluable in resolving very specific questions
- I'm planning on reaching out to communities for code reviews (your comments are always welcome btw), another pair of eyes is always helpful, although so far these have proven to be unfruitful:-
- A Dev.to blog post on Functional Enums in Java
Beerpay seems to have died so no contribution method. I'll look into replacing it.
For now, make a feature suggestion if you are so inclined.
Lastly, feel free to volunteer solutions, fixes, improvements, pull requests, documentation, technology suggestions. If you are a JavaFX/Swing guru, I'd love to see a better UI on this. Just note that I'm trying to make this, as well as a working project, a highly tested, nice codebase to work on.
EmuRox chip image by Søren Siebuhr