Developing software for early video game consoles was really hard. In this episode, we're going to explain what capabilities early video game consoles had and how creating software for them was done. Welcome to COPEC Explain Software, the podcast where we make computing intelligible. In this episode, we're going to discuss the early era of video game consoles. We're talking about the era from the first really popular console, the Atari 2600, up through the Super Nintendo. That's about the years 1977 to 1994.
So tell us a little bit about what these gaming systems were like back then.
Yes, and software is ultimately the result of the hardware limitations that are imposed on it. So I'd like to use a model console. I've written an emulator before for the Nintendo Entertainment System, so I know quite a bit about it. And it also happens to be one of the most popular consoles of this era, perhaps the most popular console of this era. By today's standards, the Nintendo Entertainment System had incredibly limited hardware. It had approximately a 2 processor. It had 2 KB. Yes, I said that right, 2 system Ram. But what it did have that gave it some additional capabilities were some really great custom chips for graphics and audio. We won't spend a lot of time talking about the audio processor, also known as the Apu, but we will talk about the PPU or the picture processing unit. The picture processing unit on the NES had a lot of great built in capabilities. It could manage a background, manage sprites, it could help do simple manipulations like mirroring or sprite flipping. It could keep track of 64 sprites on the screen at any given time. And it had Ram dedicated to maintaining those sprites. It had Ram dedicated to keeping track of the different graphical elements that can be displayed on the screen. It also had Ram for keeping the color palette for its time. When it came out in the early 80s, it was considered quite sophisticated. So that's a really rough overview of the hardware in the NES. Even with that pretty good picture processing unit and the custom Apu, it still was incredibly limited. So it was quite a challenge for early software developers to build games for the NES and other consoles like it. Yet, thinking about the NES again, some of the most iconic titles of all time were built for it. Things like super mario bros. Or the legend of zelda. How did they do that on such limited hardware?
What programming language do they use?
Well, anytime you're in an incredibly resource constrained environment, you want to go low level. You want to get as close to the hardware as possible, so there's no overhead, because you can't be using your limited hardware resources on abstractions. So almost all games programmed for these early consoles were programmed in assembly language. And we've talked a bit about assembly language on some prior episodes. So I'll link to them in the show notes. I'll also link to an episode about emulators because I've talked a little bit about how I've developed one and I also will maybe mention them again a little later. Anyway, programming an assembly language is hard. You have to write several lines of code for what would be one line of code in a higher level language. And you can't think in as abstract terms. You really need to think at the level of the machine. Assembly language is basically human readable form of machine language, which is what the microprocessor understands. But it gets worse. Not only are you writing an assembly language, but you also have almost no libraries or preexisting software available to you.
So how do they get the games onto the consoles themselves, onto the gaming systems?
Yeah, this is again how hardware connects with software and it's going to kind of connect us to what I was just talking about, about not having any layers of software underneath you. So the games on these early consoles, we called cartridges, and the cartridges were literally a hardware chip wrapped in plastic that you inserted into a receptor on the machine that then read from the hardware chip. And the hardware chip was Rom read only memory. Now, there were some advanced NES games that also had a bit of Ram and some more advanced circuitry on the cartridges. But most of the memory, most of the circuitry was just a pure Rom chip read only memory. So you insert this read only memory chip into the console and the console reads the game and the graphics data from that read only memory. But when I say reads, what I really mean is it just starts execution at a memory location in the Rom chip. There is no operating system on any of these early consoles. There are no built in software libraries. There is nothing. There is just raw hardware, including the CPU, the PPU and the Apu. And the CPU starts execution of the game on the Rom chip within the cartridge. And then everything is the responsibility of that game. There is no operating system underneath telling it to switch tasks. There is nothing that is helping display the graphics other than the PPU. So as you're going, you're manually setting up the memory within both the CPU and the PPU at every moment in time. It's as close to the metal as you basically can get programming consumer software.
And obviously it wasn't connected to the internet or anything like that, so it had to be perfect on that cartridge.
Yeah, that's a great point. There were no updates if you made a mistake in your program, it was burned into that Rom chip and tens of thousands of them were manufactured at once and distributed to stores. There were no updates if there was a bug in the game. Yeah, on the next batch of cartridges they make, they could fix that bug. And that was pretty unusual. But that first version, tens of thousands, hundreds of thousands, some of those games even sold millions of copies. People were going to have exactly the same version. And anything that the way the game shipped, that was it. It had to perfectly control the CPU, the PPU and the Apu throughout the entire time that the user was playing the game. There were no guardrails.
It sounds pretty intense and hard to do, right?
If you think about it today, when people program video games, first of all, they're working in a much higher level language than assembly, of course. And so that gives you all kinds of interesting abstractions. They also are working with frameworks like Unity or Unreal often, right? Or an in house framework if it's a commercial video game company. Now, the NES and other systems like it did in a sense, have a sort of built in framework in that. Like today, if I'm programming a game for iOS, I'm programming in something like Sprite Kit, or I'm using Unity and it manages all my sprites for me. Let's just say I'm doing a 2D game on the NES. You had that PPU with a lot of built in capabilities for managing sprites. For example, it even had a way of checking if one particular sprite called the zero sprite, was going to intersect with something on the background. If a non transparent pixel in the first sprite, the zero sprite, intersected with a non transparent pixel in the background, the programmer can get an indication of that by a little bit being set. So that's almost like a type of collision detection. So flipping sprites, moving them on the screen, having a little primitive collision detection that was being given to you by the PPU. But you have to raw control the PPU. There's no abstraction above it. So there were some real helpers here. That's what made an NES different from just having a six, five, two microprocessor hooked up to a screen and just having some raw palette of pixels like some early personal computers did. It was the magic of the PPU and the Apu that gave the NES its life, as well as the form factor of having these cartridges plug into it and the controllers and that sort of thing as well. But it was so different. What we're talking about with video game development on these early consoles is a totally different type of programming than folks are doing today who are working on commercial modern games. And it's incredible what they achieved working through such limitations. Oftentimes working with limitations is actually a driver of innovation. And we see that certainly with some of the incredible early games. I mentioned a couple of them earlier that came out in this era. And by the way, if you play a game like Super Mario Brothers, right, the physics are actually pretty good. Like the way that Mario jumps and the way that he interacts with his environment, and the animations are incredibly smooth. They did a lot with those limitations. Again, this is on like a less than 2 MHz microprocessor with 2 system Ram. It makes you think how bloated our software is today.
Some good lessons from the software of the past.
Absolutely. So another thing that kind of was an intersection between hardware and software on these early systems are what are called interrupts. Many computing systems have interrupts, including even the IBM PC series. But the way they worked on these early systems was pretty interesting, because you'd often be what's called racing the beam, the GPU, which in the case of the NES is called the PPU, if you would even call it a GPU at that time, I don't know. But the PPU is drawing basically one pixel at a time. It's going across the screen, scan line by scan line on these CRTs, which is really your television. Right. And it had a really small resolution. We're talking about 256 by 240. But it's going across every scan line, drawing all of those 256 pixels. And it does that 240 times. Right. And it's very hard. There were a few games that did it, but it's really hard to actually change the graphics while it's drawing that whole frame, while it's drawing all of those 256 by 240 pixels. So the only time you can really update the graphics is when it's done. And this is a period that would be called Vblank vertical blanking. It's when you got to the bottom of the screen, there would be kind of a period of about 20 scan lines, which equates to 2273 CPU cycles, where you can actually go and change the graphics. That's not a lot of time. That's literally 2273 instructions. Now, the NES ran at 60 frames per second, so there would be 60 times a second that you would have 2273 CPU cycles to go update all the graphics. How would your program know that this was the time to go update all the graphics? Well, there would be an interrupt. It was a hardware interrupt, and it was one that couldn't be stopped. So it was called a non maskable interrupt, an NMI. And it would fire and say, hey, it's the Vblank time to your program. And a certain part of your program would automatically be called just based on a memory location when that NMI executed. And so it would jump to that part of your program automatically. Again, this is hardware control. There's no operating system, there's no control software. But this hardware control would cause this part of your program to run. And that part of your program in those 2273 cycles would have to go and update all the graphics. I wanted to talk about this because you see how programming these early machines was a true symbiosis between hardware and software and really dictated by the limitations of the hardware, which is very different than how we program today. Today. We're always programming in abstractions, and we're often, often not even thinking about the low level hardware. Not too much, at least. Maybe if we work on engines or we work on the graphic subsystems, we're thinking more about the hardware, but often that's going to be a separate job or turned over to a framework maker like Unity or Unreal, instead of the responsibility of the N programmer. So I think when we look back on this era, we can just be amazed by the achievements of these early video game programmers. What they did was such limited resources, but what stands the test of time? People are still playing these games today, I think, is really the gameplay. It's incredible the type of graphics and even sometimes physics that they got out of such limited resources. But what stood the test of time and we're still living with are the genres that they invented, from platform gaming to RPGs, et cetera, et cetera. They all existed there on these early consoles, and they did it all with such limited hardware resources. Okay, thanks for listening to us this week, Rebecca. How can people get in touch with us on Twitter?
We're at COPEC Explains Kopecexplains, and I.
Want to remind you to follow us on Apple podcasts or Spotify or wherever you're listening to us. We come out with new episodes about every two weeks. And if you enjoy our podcast, don't forget to leave us a five star review. It helps other people find us. Have a great day.
Bye. You close.