The NES Homebrew Scene
tedium.co
tedium.co
I couldn't think of a good name, but I was modding Kid Icarus at the time, and it's in .NET, so I just called it IcarusNet. It was primarily for ROM hacking, but as far as I know, it should be suitable for writing something from scratch in conjunction with tile editing programs and maybe other things you'd need.
Not nearly as advanced as NESMaker (very impressive from the looks of it) seems to be, but maybe a middle ground for someone who wants to write a game more to the metal but also wants something more graphical with the same "one click assemble/run" mindset.
Comes with instructions for a sample project to make an edit to a freely available ROM in less than 5 minutes.
https://github.com/ldyeax/IcarusNet
Since then I've heard that license might have some problems for software, so I'll change it if the need arises.
[0]: https://github.com/cc65/cc65 [1]: https://hub.docker.com/r/philhsmith/cc65/
On the NES however, every line of code is yours. There's no such thing as libraries, operating systems, or frameworks. They don't exist. It's refreshing.
One of the big problems of modern programming is how easy it is to add complexity. As Charles Moore once said:
>"Simplify the problem you've got or rather don't complexify it. I've done it myself, it's fun to do. You have a boring problem and hiding behind it is a much more interesting problem. So you code the more interesting problem and the one you've got is a subset of it and it falls out trivial. But of course you wrote ten times as much code as you needed to solve the problem that you actually had."
It's easy to add complexity on modern systems, but it's hard on the NES. The programming too clunky; it's too much work to anything but simple things. For that reason, it's far more common to simplify the problem and reduce features rather than add them. It's a wonderful thing.
Each part of a bacteria, relative to its mass, may be more cost effective than that of a mammal. I'd much rather be the latter.
Where before you had a GUI part talk to a CLI part via pipes, now you have them talking to each other via a XML based bus mediated by multiple daemons (one for the bus, one to uphold a fine grained security layer again using XML and JSON).
Arduino, ESP286, ESP32, <pick your own flavour>.
And since we are in the context of games and Nintendo, something like Arduboy.
Like... Please move to an ARM MCU with a C codebase.
Of course you can pick up old parts which fell off a truck for cheaper but I'd rather not do that when I depend on these parts for many years to come.
That's why those applications use less known 4-bit processors.
Using c does come at the cost of some code compactness, but you can selectively optimize as the need arises.
Both the Arduino libs and Espressif SDK are fairly big chunks of code.
Yes, you can program AVRs without libs too, but you did specifically say Arduino. It is also my understanding that ESPs are both bit obscure and fairly complex beasts to be managed without SDK.
While there are still some nice cases of simplicity in the embedded world, the complexity and layers of libraries and frameworks model is encroaching there too.
http://fingswotidun.com/avr/AvrAsm/Testbed/
It's pretty much a project to scratch the itch being described in this thread. It gives you an in-broswer 8-bit AVR based fantasy console and Assembler.
https://medium.com/@caspervonb/the-internet-is-at-the-mercy-...
That said, when K C Green ran a Kickstarter for a plush This Is Fine dog it took in more than ten times what he was asking for; how much of that went into his bank account as profit, I dunno.
If KC Green made an image macro and posted it on Reddit it would be one thing. But they didn't, they made a comic and put it on their own site.
I can't speak for KC but it's just bad taste not to cite things that are flat-out copyright somebody else.
I would say that there’s still “other people’s code” that you rely on—that code is just reified into ASICs you drive with control messages over IO ports, rather than being OS system-service daemons you drive with control messages over IPC.
Also keep in mind that, despite the lack of a forced OS or BIOS on the system itself, Nintendo’s SDKs included snippets or code samples (or sometimes complete small libraries as modifiable assembler source), and developers shared others around when they came up with them to solve a particular problem.
(Later on, in SNES/N64/GameCube era, Nintendo effectively handed you a whole library exokernel worth of precompiled, static-linkable libraries for you to use, too. The NES was too small for that, though.)
I once stuck my nose into Game Boy Advance homebrew and was happy to find it can be the same there. Every piece of the hardware is memory mapped. That means, given a reference of the mapped addresses and struct definitions, you can do whatever you want with the machine without any magic, black-box external code.
NES games never wrote their own scrolling logic, or there own graphics logic. They wrote tile values into a background table and then told the NES how much to scroll the playing field, and the NES rendered and scrolled everything automagically.
NES games never drew their own sprites. They just said "Hey NES, write the sprite at this x and y location" and the NES did it.
Audio worked the same way.
Honestly, coding for the NES would be similar to working with a simple 2D graphics library. So I don't know if it would be accurate to say "every line of code is yours" on the NES. It's more just that the "libraries" used were implemented in hardware instead of software.
Yeah, but the hardware is so limited with weird corner cases that writing a bitblt might be easier. For example, some games have to reconfigure their sprites at the beginning of every horizontal scan line to overcome the hardware limitation on simultaneously displayed sprites (8).
For example, concepts like a scroll register don't typically appear in an abstracted API. They're a hardware detail that happens to assist in implementing a smooth scroll by reducing the necessary computation. But they aren't a "smooth scrolling API" because it works on the tilemap data only - you can also have sprites scroll. That necessitates a software implementation specifically for the task of sprite rendering. Witness the numerous NES games that either let sprites disappear when they hit negative X coordinates or put up a convenient black bar to hide it.
I'm always thoroughly impressed with how complicated and knowledgeable the people who work on these topics are.
I don't even use the product, but I love reading the Dolphin blog [0] because they write about fairly complicated topics in a way that's pretty approachable, and it always makes me appreciate how much I don't know about these topics.
While I feel like it would be difficult-but-not-impossible to be a contributor to say, the linux kernel (this is probably me grossly oversimplifying the process), I think I could spend the next year diving into graphics programming and basic hardware topics and still not contribute in any meaningful way to a project like Dolphin.
Articles like this and the Dolphin blog definitely make me realize how much I don't know.
It's a lot of work. I've managed to get data from Tiled into my ROM image, and I'm working on figuring out an architecture for scrolling and displaying a status bar.
Implementing scrolling and a status bar sounds simple but is actually a total pain. You only have two screens of tiles to work with, which can be arranged horizontally or vertically, and anything more complicated than scrolling in a single direction (including status bars) requires adjusting the scrolling registers between scanlines, and making sure that your status bar is in a different part of the tilemap (called "name tables") than your world.
A common way to accomplish this is to lay out your graphics memory so a certain address line turns on and off once every scanline, and then putting a chip (called a "mapper") on the game cartridge which wires that address line to a counter, which drives a CPU interrupt line. Simpler games like Super Mario Bros. don't need this extra chip, but you only get a single status bar + scrolling in one direction only. Games with scrolling in both directions often display graphical glitches on the edge of the screen, like Super Mario Bros. 3 (look at the right edge of the screen).
This is unnecessary on newer consoles, and less painful even on the Sega Master System.
This is so true as a life principle!
I once read a book about the development of laser guided bombs [1], and in it it talked about how Texas Instruments made the first viable prototype [2] on a shoe-string budget even though they were competing against a large government contractor with a huge budget.
Because of the budgetary constraints, TI couldn't afford multi-million dollar wind tunnels for testing, so they built scale models of the bomb and dropped them into swimming pools, performing mathematics transforms on the results using the drag coefficients of water vs air. They came up with a bunch of other innovations as well, such as the shuttlecock seeker head and made a superior product that vastly outperformed the high-budget contractor.
[1] https://www.amazon.com/Weapons-Choice-Development-Precision-... [2] https://en.wikipedia.org/wiki/Paveway
Tools are, simply put, devices that increase a user's leverage.
We live in a world full of tools capable of leveraging against life. We also live in a world with individuals and groups who - for whatever reasons - choose to use that leverage.
We can't get rid of tools like this. They are very straightforward inventions, especially as technical knowledge increases. The simplest nuclear fission reactor is a bomb. That does not make nuclear fission fundamentally worthless, and whether you agree that knowledge about it is a "good" or not, that knowledge is not going to simply disappear.
> choosing to believe the claim that killing those people will save lives alters neither the purpose nor MO of the tool.
How a tool is used does not change what it is or what it does. It does, however, define the purpose. If the purpose of killing someone is to prevent that individual from taking another life - or several other lives - then the purpose of the tool used is to save lives. The goal for perfecting a tool that is to be used for that purpose is to minimize the amount of lives taken, and damage done. That means a "better" bomb takes fewer lives, saving more.
If you choose to believe that an individual taking action against the life of another has not forfeit his/her own right to live, then you might consider this tool to have no legitimate purpose. Frankly, I disagree, and hope you will reconsider.
With PGMs you can take out a bridge with pinpoint accuracy in the middle of the night and nobody dies at all (directly, at least).
In another reading, absence of limitations would be limiting, still, which would be paradox.
Also, maybe creativity isn't the same as being a good programmer. Creativity may get you out of a bind or into a new area, but I think being a good programmer is founded on many mundane characteristics, such as consistency and ability to conform to others.
This past year, however, I decided to take up a little retro project based on the NES. Its best described as a "video game music player alarm clock", using some authentic hardware. It uses the CPU from an actual NES to faithfully synthesize music from actual NES games, while building the surrounding system out of modern components.
First prototype in action: https://www.youtube.com/watch?v=izMFPKmD5ZU
Blog posts detailing the project: http://hecgeek.blogspot.com/2018/02/nestronic-1.html http://hecgeek.blogspot.com/2018/03/nestronic-2.html
You will, of course, need to know what bits to set at what addresses to make the NES auxiliary chips work and do what you expect them to do and that may represent some work but that complexity is from the platform, not the language. You can have a library (or a set of macros) that deals with it written in any language you can compile for the platform.
Solving the towers of Hanoi puzzle can be done completely mechanically (exercise: derive the really simple algorithm). Programming in such a constrained environment is something where you have to think for yourself, since I am not aware of any mechanical solution.
That's the relaxing part.
But remember: there is always a lot of state flying around that's not exposed to the programmer through architectural registers.
For example using something like MASM or TASM back in the MS-DOS days was like having your own high level language.
So you end up creating a kind of DSL with those macros.
That's precisely why I would qualify ASM as "tricky" and "tedious". You're bogged down in the tiny details that nowadays a compiler would probably solve as well (or even better) than you do. If you want to express "I want to make a function that adds two integers" then yeah it's trivial. If instead it's "I want to iterate through the leaves of a binary tree and compute its standard deviation" then have fun; good luck.
"This is a multiplication by 5, it's pretty expensive, probably better off shifting by two and adding once. Oh but then I need an intermediary register, do I have one available?"
"I guess I could inline this bit of assembly here instead of making a function call. Oh but wait now I need to re-do my register allocation to match."
"I need to reserve a bit more stack space to bank this register, let's modify my function's prelude and prologue to match."
Ain't got no time for that.
I think writing assembly is a skill any coder should have, especially if you usually deal with close-to-the-metal languages like C, C++ or Rust for instance. I think having a good grasp of assembly will make you a better coder, if only because it'll let you read the assembly output of your compiler to figure out what gets optimized and how (and also maybe what you could change to speed things up). There are also a few situations where writing assembly is the right solution.
That being said you'd have to pay me a lot to write a full application in assembly, regardless of how many layers of macros and pre-processing steps I'm allowed to use (unless gcc is allowable as a pre-processing step...)
If you code something for artistic or "competitive" reasons then of course it makes complete sense. Like people making 4KB demos, speedrunners or people folding thousands of paper cranes. There are no invalid paths if you're an artist.
On the other hand if you consider it from a practical engineering perspective then there are few use cases where I'd go with ASM nowadays, well optimized C code will be easier to write, probably nearly as fast, way easier to modify and maintain and much more portable. Some paths are wildly superior to others if you're an engineer.
But we are talking about the 6502 inside the NES, running at less than 2 MHz, with one accumulator and two index registers, a couple status flags and an 8-bit stack pointer within a 256-byte stack. It's a simple machine, for simpler problems.
And yet, guys like Paul Lutus were doing real-time 3D wireframes in FORTH, with fast 8-bit scaled trigonometric functions (no floats involved). It was pure badass of a magnitude not heard of since.
My own contribution was a windowing library for the Apple II that did fit in 1024 bytes and ran self-modifying code to display overlapping windows.
I will typically build something out in a high level language, profile to see where the time is going, and take a closer look at the algorithm first to see if it's sensible or some different approach should be taken. If it's an appropriate algo, then it's time to look at the implementation to see where we can shave cycles.
For the most part, even if you're talking to hardware that requires exceedingly precise timing (interface/bus protocols, certain chips), C will probably do the job. (It's no coincidence it was referred to as "universal assembly language".) Only where one is absolutely starved for resources (as the NES, and many 8-bit systems were/are) is ASM necessary.
"high level when you can, assembly when you must"
I was already following that on MS-DOS with its 640 KB, with all Basic, Pascal, C and C++ compilers from Borland and Clipper.
Although I did spent one year still focused on using TASM for everything and playing how much I could cram into a COM file.
Assuming this is a recurring problem, I'd just use two libraries - a binary tree and a floating point one (I cut my teeth on the Apple II+, so I could count on FP routines already in place in the ROM. If a tree library is not available, writing a tree walker is not a particularly difficult task.
Libraries, subroutines and macros were a huge helper then.
> I need an intermediary register, do I have one available?
If we are talking 6502, the answer is "no". You had page zero, which was almost as good as having 256 8-bit registers.
It also applies to using languages like Java and C#.
Occasional devs might not be aware of it, but there are ways to see what the JIT/AOT compilers generate.
Meaning that if they have to care about memory structures, or even variable types (just look at how popular JS and Python is), they see it as a bothersome language to work with.
End result though is software that balloons to multiple gigs and maxes out a gigahertz CPU just by being launched and sitting idle.
I miss the old assembler. It could just be that I have a poor memory, but with 8/16-bit assembly, I could remember almost everything about my toolset and focus on the problem.
With modern APIs and languages--even modern assembly languages--I spend more time googling than anything else.
> focus on the problem
Think harder, you might remember that you weren't solving many problems either.
Modern hardware raised the stakes and forced us to spend more time (in some cases, the majority of the time) on packaging and presentation--even where it didn't really matter that much after the sale.
I'm not talking iPhones were a human interacts with it constantly. I'm talking control systems, where after the sale, human interaction is simple and rare.
Those CPUs already started being complicated enough to make ASM programming less attractive. IIRC, on 286 the string copy instructions were faster than the DMA transfers people used on earlier PCs and, because of that, if you wanted to have optimal performance, you'd need to check which CPU it was running and branch accordingly to the best code path.
The Intel C Compiler still does that. It compiles multiple versions of your code, each optimized for different processor versions.
The way some instructions were neither macros nor actual CPU instructions always felt strange to me.
I remember back when I first used Windows 95, opening programs was very snappy and I was impressed. I imagined Windows of the future being even snappier, but somehow the opposite has happened. Now every application takes a long time to boot up, check for updates, etc just because they use orders of magnitude more resources. I long for apps with instantaneous startup times, no loading screens, and small footprints
I also believe game designers/developers should work on at least one retro game or mod for similar reasons. Teaches them how to actually design levels without thinking about the artistic side, and (thanks to some brutal moderation requirements on the sites hosting this stuff) forces them to get better at game design rather than just walk through Steam/the app store's non processes.
I really like your idea of encouraging people to try getting code running on older machines. I really understand that someone who didn't cut their teeth on a 3kB RAM machine won't have the same appreciation for constrained memory computing, and I think your suggestion is a great way to introduce them to it.
Thanks for the thought!
No you don't need a video on your login screen.
I as a freelance developer sometimes make releases whose sole purpose is to refactor/slim down/increase performance with no new features. Yeah, some of my users are disappointed I didn't prioritize X feature they wanted, but it helps mitigate tragedy of the commons a little.
Individually the users are well-meaning with their feature wants/needs, but collectively all the different feature requests can turn your app into a bloated monstrosity if you aren't careful.
The difference can be felt when comparing a game like Super Mario Bros running on an emulator with a typical LCD screen to running on original hardware with a CRT monitor. The emulated version is so sluggish it feels like you're playing underwater!
The techniques haven't been lost - if anything there are probably more people who know how to do those things today than there were in the past.
Typical LCD monitors are undeniably worse in many ways than the CRTs they replaced, but again, most customers turned out to prefer the convenience of the LCD on the whole. Nowadays with the rise of 144Hz monitors those rare users who care a lot about gaming latency do have an option.
I would expect the NES to perform similarly to the Apple, since it has the same CPU (6502) and also uses a CRT display.
Perhaps the last refuge is battery-powered microcontrollers.
But even then, if they have up to 512 KB, is like having the same tooling as on the Amiga, Atari, PC (MS-DOS) on a needle size CPU.
For younger generations, you can check on YouTube what we managed to do with 512 KB on those systems, even when using higher level languages.
http://www.pouet.net/prod.php?which=69648 / https://www.youtube.com/watch?v=gWVmPtr9O0g
The NES homebrew scene is pretty cool and the tools and languages have come a long way. One interesting avenue that might be work exploring is to use code generation and CSPs to generate and shrink code.
It's a lot of fun. It's why I like the PICO8. Constraints are interesting.
I just wish I still had my old BASIC code for games I made on my Amiga back in the day...
Constraints are also helpful when working towards a sense of mastery.
Look at a modern operating system (or console) for that matter. So much capability, so much complexity. You'll never learn it all, never be able to master it.
Heck, just truly understanding the machine code of a modern processor, and knowing everything it does and can do is quite a daunting task.
These older 8-bit systems (NES, C64, etc.) in contrast are much easier to completely understand. If you are willing to live within the limitations, you can create something really awesome, and be able to leverage the full extent of the system's capabilities.
That provides enormous satisfaction to some.
Got an example project at
It says something about the legacy of the NES that most homebrewers continue to make games for the system for reasons other than nostalgia. It’s mostly because they love the NES.
“I’ve always wanted to create NES games, ever since I was a kid. I remember sitting around drawing maps on paper, daydreaming of what my designs would be like to play,” explained Nathan Tolbert, a relatively new figure to the NES homebrew scene who’s already built a couple of titles for the annual NESDEV competition.
So...nostalgia.
One creator, Antione Fantys, wants to bring back some of the elements from retro games that don’t seem to exist in the modern generation. Because the NES is the most iconic of these systems, he enjoys programming with it, citing the limitations of the system as a means to creating the most accurate representation of a retro game as possible.
More nostalgia.
The article pretty much proves these homebrews are the product of nostalgia. Not that there is anything wrong with that.
Never had an NES growing up, never played one until I got into NES dev. I was turned onto it by a classmate. We're both too young to have had the NES growing up, so we simply couldn't be a nostalgia play. There's a lot of folks who get into because it's surprisingly approachable, and scratches the itch of "make a game." TFA just had a bad quote...
I don't really understand why people view interests based on nostalgia as a weakness. Being nostalgic doesn't have to mean that life isn't good or that things were better once upon a time.
Like what you like, do what you do, and enjoy what you enjoy without apology!
Nothing about what I did, nor wrote was driven by a longing for the days of yore, mine or otherwise. I enjoyed learning to write software for the 6502, it was a simple instruction set, fairly clear, concise, and simple.
I haven't written 6502 in a number of years, and gave my NES collection to a friend last year. That I have an old PCB on my desk, yes, is nostalgia.
However, I agree with you, trying to capture past enjoyments and in cases like this, continue to make new memories and fun times, go for it I say!
Hey, why isn't anyone reading our article?
"Crazy! The NES Homebrew Scene Thrives Like You Wouldn't Believe!"
"When You Read About These NEW Homebrew Games, You'll Never Game the Same Again!"
"I Played NEW Homebrew Games - What Happened Next Blew My Mind!"
Now they'll read it.
So, nostalgia is a big part of the NES appeal, but there may be other factors as well.
https://www.twitch.tv/clearvus
recordings are posted on youtube: https://www.youtube.com/watch?v=XwGj1ciSAtw
https://www.kickstarter.com/projects/1316851183/nesmaker-mak...
Simple versions of these things are not as insurmountable as you think: just put your foot on the first step :-)
My top score in 2min is 500,000+.
Having recently discovered OpenEmu, I'm trying to track down good homebrew/freeware games.
Honestly, I'm glad Nintendo got knocked down a peg on their last few systems. I'm just not happy about what they taught their competitors.
Having people accept NES-style pixel art is a boon to indie devs. Games like Super Meat Boy have higher res 2D graphics but is still a similar aesthetic. Low-fi poly is also a retro art style. However I've noticed that low-fi poly games are still rendered in high resolution and using more advanced lighting techniques so still requires more work than low-fi 2D.