1. 29

I’ve been having lots of fun working on this for the last few weeks. Only a few games are actually reasonably playable so far, but it’s been fantastic getting a glimpse of the insides of the NES/6502 (for some definition of fantastic that involves getting repeatedly humbled/frustrated/rewarded/amazed).

  1. 6

    That looks fun! Any particular unexpected NES hardware quirks you found?

    1. 10

      Definitely! I think it is particularly interesting to see some of the tricks used to get around with so little resources. For instance, there is only 2kB of CPU ram and 2kB of video ram, with usually ROM on the cartridges. One of the things I found specially clever is the use of “mappers” on the cartridges. Mappers allow memory banks to be switched by the program, so that different memory banks can be accessed on the same memory address by both the cpu and ppu. This allows cartridges to pack more data than would be initially addressable by the console. This is one of the reasons why the NES was able to handle more complex and pretty games. Take for instance Super Mario Bros. 1 (an older game, with a very straightforward cartridge wiring) and Super Mario Bros. 3. They feel like even different platforms, also because smb3 was able to get away with using a more complex mapper.

    2. 5

      Thanks for showing this.

      I had fun recently writing my first CPU emulator (for the Z80) in go, which morphed into an assembler, disassembler and ultimately a simple ZX spectrum emulator. https://github.com/jbert/zog

      Got as far as a few key games running well. It is the most fun I’ve had with a compiler since the cryptopals challenges.

      To which I should probably return since there are more and I should have a go at learning some rust.

      1. 5

        Another “quirks” question: did you find any unexpected quirks of Go that made writing this emulator harder or easier?

        1. 5

          In this particular case, it feels like the code isn’t too far from what C code would be: here are some basic data structures and here are some functions that operate on them, mostly on the bit level. No fancy concurrency models nor exciting constructs. I think given the fact that this is an inherently low level program, most nicieties from Go weren’t immediately needed.

          I did use some inner functions/closures and hash maps, but could’ve just as well done without them. The bottom line is that the language didn’t get in the way, but I didn’t feel like it was enourmously helpful, other than making it easier to declare dependencies and handling the build process for me.

          1. 4

            Did you run into any issues with gc pauses? That’s one of the things people worry about building latency sensitive applications in go.

            1. 3

              Not the OP, but I would assume this kind of application generates very little garbage in normal operation.

              1. 2

                The gc pauses are so miniscule now, for the latest releases of Go, that there should be no latency issues even for realtime use. And it’s always possible to allocate a blob of memory at the start of the program and just use that, to avoid gc in the first place.

                1. 2

                  The garbage collector hasn’t been an issue either. Out of the box, I had to add artificial delays to slow things down and maintain the frame rate, so I haven’t done much performance tuning/profiling. I am interested in scenarios where this would be critical though.

                  1. 1

                    Go’s GC pauses are sub-millisecond so it’s not an issue.

                2. 3

                  Interested in this as well. I’ve toying with the idea of writing a CHIP-8 emulator in Go and would love to hear about how is the experience of writing emulators.

                  1. 3

                    I did exactly this as a project to learn Go! I used channels in order to control the clock speed and the timer frequency and it ended up being a really nice solution. The only real hangup I had was fighting with the compiler with respect to types and casting, but having type checking overall was a good thing.

                3. 2

                  Thanks for sharing this. :-)