It appears that in my current semester, for the programming class, we have to learn a new programming language. What’s more, we actually have to blog about our progress in learning the new language and basically “making it our own” as the instructor put it. I assume the blogging will be done on another platform but if English is allowed, I’ll just copypaste it over to this blog. For now, I suppose this is blog post 0.
We’re following this book called Seven Languages in Seven Weeks by Bruce A. Tate, and the book introduces the following languages: Ruby, Io, Prolog, Scala, Erlang, Clojure, and Haskell. From what I understand, we need to pick one of these.
Now, to be honest, I haven’t looked into most of them – just Ruby and Haskell, and the impression I have so far is that Ruby’s syntax looks really simple, and Haskell’s syntax made me hate life. I absolutely have no clue about the rest. I’ll have to continue reading the book and look into the remaining languages next week.
Aside from the aforementioned languages, I’m also interested in Python, Rust, and C#. Python seems simple and fun to learn. Rust also seems interesting to me because it actually has a good following and the syntax looks readable. To be perfectly honest though, I haven’t looked into their practical uses yet.
Finally, C# also interests me but I can’t really put it in the list of languages I’d like to learn for this course – I already know quite a bit about C# as it’s my go-to language when I program in my free time. I even use it in the programming course despite the course being made for Java.
I should ask the instructor if we’re also allowed to learn other languages besides those seven, or if we’re allowed to learn multiple (why not?). I think that’d be really cool as well as challenging.
The namesake is inspired by “Snes9x” (I never knew what the 9x really meant). I didn’t want to simply call it Super Chip-8 because there’s a variant of the Chip-8 called SCHIP (Super Chip) and it could cause confusion, and conveniently enough the name already had a number so I just stuck an “x” at the end.
How the idea came to be
Writing a (crude) SNES emulator has always been on my wishlist – so I started doing research on the SNES as well as emulation in general. Google seems to have taken notice of my emulation-related searches. During my daily routine of checking the Google app for stories to read, it suggested to me this certain article:
Upon seeing the title alone, I had three questions in mind: “What is Chip-8”, “what is Rust” and “what is WebAssembly”? I looked into the latter two and they didn’t really interest me. Looking into Chip-8 was another story, though.
I seem to have a soft spot for emulation, assembly and old/retro consoles in general. So when I read about the Chip-8 I noticed how simple it was (it’s considered the “hello world” of emulation) and I got really into the idea of writing an emulator for this. Then I found out there’s already like a thousand emulators for this. It was then that I had this impulsive thought: The Chip-8 is so simple, it could probably run even on the SNES. Amused by my own idea, I set up the project directory.
Setting up the project
To work on this project, all I needed are three tools:
And… that’s about it. The rest was up to my coding and problem-solving skills.
Prior to this project, I had never finished a SNES homebrew ROM before. The greatest extent of my homebrewing is activating the screen and displaying things, but in terms of gameplay or controller inputs, I did nothing. This was going to be a whole new experience. I decided to approach this project in my own way – take a really safe approach and define every RAM address, and (almost) every magical number. I also decided to not optimize the code, because I think I would’ve lost control over my code really fast if I did that from the very beginning already.
The display of the Chip-8 is 64×32. The display of the (NTSC) SNES is 256×224 by default. p4plus2 gave me the idea to make the screen mode 7. It has a very simple graphics format (1 byte per pixel basically) and you can scale the screen, so I could make the Chip-8 display 256×128. People won’t have to squint their eyes when using the emulator, at least. Because the (scaled up) horizontal resolution is a perfect 256 pixels wide, I decided to use HDMA to color the screen boundaries.
In order to emulate the Chip-8, I had to allocate some RAM for its registers.
These are all in the SNES direct page (except for the memory), which would allow for slightly faster access to the registers.
I also allocated some RAM for opcode parameters. Each opcode could be ‘dissected’ into 6 variables: The opcode itself and 5 parameters. All of these variables are filled in regardless of the opcode currently being processed.
Inside the main game loop, I added a subroutine call to an opcode parser. Because every opcode is exactly two bytes, it was a matter of reading an opcode, then increasing the program counter by 2 to get to the next instruction.
I made use of a pointer table which is used by !Opcode. Each opcode will have its own function, but there are certain opcodes which act as a ‘container’ for another group of opcodes. The greatest example is opcode $08 – “Arithmetic”. The SNES – in my opinion – is pretty okay with pointer tables, and I had no problems with making yet another pointer table for those specific container opcodes.
My biggest problem was thinking of a proper solution for the Chip-8 input. Officially, the system has sixteen keys. The SNES only has twelve and you can’t use all 12 for conventional input. Start and select are in the middle of the controller and you’ll have to reach them with your thumb, forcing you to stop using the D-pad or the ABXY buttons. This leaves you with 10 buttons, and there’s no real way to divide 16 buttons over 10 buttons.
Then I got the idea of using button combinations. You could map the 16 keys to the ABXY buttons by using button combinations with the L+R buttons:
However, using this controller scheme for every single ROM would be very as awkward and uncomfortable. So I got the idea to make a custom controller scheme for every playable ROM.
dw CDefault : db CDefault_end-CDefault ;boot
dw CDefault : db CDefault_end-CDefault ; fifteenpuzzle
dw CBlinky : db CBlinky_end-CBlinky
!CUP = $0800
!CDOWN = $0400
!CLEFT = $0200
!CRIGHT = $0100
!CY = $4000
!CX = $0040
!CB = $8000
!CA = $0080
!CL = $0020
!CR = $0010
dw !CY : db $01 ; Y
dw !CX : db $02 ; X
dw !CB : db $03 ; B
dw !CA : db $0C ; A
dw !CY|!CL : db $04 ; Y + L
dw !CX|!CL : db $05 ; X + L
dw !CB|!CL : db $06 ; B + L
dw !CA|!CL : db $0d ; A + L
dw !CY|!CR : db $07 ; Y + R
dw !CX|!CR : db $08 ; X + R
dw !CB|!CR : db $09 ; B + R
dw !CA|!CR : db $0e ; A + R
dw !CY|!CL|!CR : db $0a ; Y + LR
dw !CX|!CL|!CR : db $00 ; X + LR
dw !CB|!CL|!CR : db $0b ; B + LR
dw !CA|!CL|!CR : db $0f ; A + LR
;generally accepted directional keys
dw !CUP : db $02 ; up
dw !CLEFT : db $04 ; left
dw !CRIGHT : db $06 ; right
dw !CDOWN : db $08 ; down
dw !CUP : db $03
dw !CDOWN : db $06
dw !CLEFT : db $07
dw !CRIGHT : db $08
dw !CA : db $0F
dw !CB : db $0F
dw !CY : db $0F
dw !CX : db $0F
It involved extra work, but in the end, it was worth it. Technically the emulator supports all 16 keys, but at the same time, you can set intuitive controls for each playable ROM.
In the end, I am surprised at myself for being able to complete this project at all. I think the very idea of coding an emulator for the SNES kept me going on. Personally, I think it’s a pretty crazy idea.
SMWCentral’s C3 event was also nearing so I thought it was the perfect opportunity to finish a project and show it off to everyone.
The fact that I can tell people that I coded an emulator for the SNES, no matter how simple the Chip-8 system may be, is something that I can be proud of.
Most SNES ROM hackers probably have realized how limiting the SNES sometimes can be. You can only have 8 (H)DMA channels, the amount of OAM tiles on the screen is limited (think of the 33’s Range Over and 35’s Time Over limitations), the VRAM sometimes is small when you have a level with many varying graphics, etc. I guess that is understandable. Consoles didn’t have that much processing power back in the days due to limited technology, which was possibly also expensive.
Limited ROM space is also a major downer. Nintendo fit an entire game into a 512kB ROM – Super Mario World – using various tricks. They used LC_LZ2 compression, Reduced graphics from 4bpp to 3bpp, they used RLE compression, etc. They could only afford so much ROM space. As time passed, ROMs got bigger and bigger but the ROMs were still small enough to not unlock the extreme potential of the SNES (like allowing movie sequences and/or making quick time-event games).
The PPU registers are also pretty limiting. Certain registers can only be written to during V-blanks (like writing new graphical data). Write too much and you risk flashing scanlines at the top of the screen.
Sometimes, certain SNES limitations could be bypassed. There were enhancement chips which allow bankswitching for more ROM space for example, or chips which allow you to write bitmap data directly like the SuperFX. However, even with the enhancement chips, some limitations just don’t change. You can’t increase the amount of audio channels, you can’t increase the amount of layers, you can’t increase the amount of sprites shown on-screen, etc.
Finally, coding for the SNES has always been a pain to begin with. You code in ASM (Assembly). You write a bunch of LDAs and STAs and hope things work out. It’s very unreadable.
A question I had in mind for a long time is “How do I overcome the SNES limitations?” Of course, there are multiple answers for that, ranged from something as simple as “just don’t attempt it” to “even if you overcome it, it’ll have limited practical use”. So I decided to look at it from another point of view – emulators.
It should be possible to modify emulators to include less limitations, but the concept of “ROM hacking” wouldn’t remain the same anymore. Sure, you can allow 512 or more layers, but obviously this won’t run on the actual SNES. It’ll pretty much be like building your own game engine, and you’re still limited to ASM of course.
This idea gave me another idea. How about building a game engine based on the SNES’ hardware, but with its limits gone? You’d have infinite graphics space. You’d have infinite layers. You’d have infinite music channels. Infinite palettes, etc. You can have as many HDMA channels as you want affecting layers, brightness registers, and so on. You won’t have to allocate RAM for variables manually (because declaring variables in a high-level language just picks a free RAM address for you). You can display as many sprite/OAM tiles as you want to display as long as your graphics card can handle it. And so on.
For example, want a level with very neat parallax scrolling? Pick 5 layers with 4bpp graphics. Or pick 5 layers with 8bpp graphics with one set of palettes for each 8bpp layer. Or you could have a mode 7 background while you have a fully playable level.
Only question is, how would this be built? Take bits and pieces from emulators and make your own engine, or start completely from scratch? Personally I’d attempt the former, but I wouldn’t even know in what language to start. Oh well.