"It really is a great feat ... that any of the games ... worked at all"
June 17, 2021 11:48 AM Subscribe
Kids today, with their multi-gigabyte graphics cards and CPUs capable of billions of operations per second. In my day, the Atari Video Computer System (later known as the 2600) had 128 bytes of memory and a single 1.19Mhz processor responsible for both executing game code and manipulating and drawing graphics. How, you may ask? Well, it was a little tricky. (SLYT, 38 min).
Atari programmers had to "race the beam" - write code that performed almost all of the game calculations in the time it took a CRT's electron gun to move from the lower corner back up to the top, and that could write the pixels on-screen in real time. In 2009, writers Ian Bogost and Nick Montfort wrote Racing the Beam: The Atari Video Computer System, which described this process in exquisite detail. YouTube channel Retro Game Mechanics Explained has published a video breaking down the timing required to get games and title screens picture perfect.
Atari programmers had to "race the beam" - write code that performed almost all of the game calculations in the time it took a CRT's electron gun to move from the lower corner back up to the top, and that could write the pixels on-screen in real time. In 2009, writers Ian Bogost and Nick Montfort wrote Racing the Beam: The Atari Video Computer System, which described this process in exquisite detail. YouTube channel Retro Game Mechanics Explained has published a video breaking down the timing required to get games and title screens picture perfect.
You had 128!? The story of Mel.
Sheesh, the kids didn't even need to toggle in a bootstrap loader.
posted by sammyo at 12:33 PM on June 17, 2021 [3 favorites]
Sheesh, the kids didn't even need to toggle in a bootstrap loader.
posted by sammyo at 12:33 PM on June 17, 2021 [3 favorites]
On the one hand it's already 38 minutes long, on the other hand I think he kind of blitzed past 2600 sprite handling entirely. I assume the whole bit with ET's face is a bunch of memory reads and writes, but he didn't take any time at all on the usual assembly instructions, focusing on the actually tricky bit of setting up the registers properly.
posted by Kyol at 1:00 PM on June 17, 2021 [1 favorite]
posted by Kyol at 1:00 PM on June 17, 2021 [1 favorite]
This reminds me a little bit of SethBling's video from four years ago, where he got an Atari emulator working within Minecraft.
One of the highlights was that he actually visualized the cartridge's entire memory of 1s and 0s as stone and dirt blocks, so it was possible to watch the emulator read and rewrite to memory one byte at a time.
posted by The Pluto Gangsta at 1:07 PM on June 17, 2021 [4 favorites]
One of the highlights was that he actually visualized the cartridge's entire memory of 1s and 0s as stone and dirt blocks, so it was possible to watch the emulator read and rewrite to memory one byte at a time.
posted by The Pluto Gangsta at 1:07 PM on June 17, 2021 [4 favorites]
The static six-sprite trick is great, but it was perfected with David Crane's "Dragster" in 1980. You can also use this trick for a six-digit score/odometer display.
Now try doing two multicolor sprites overlapping a playfield, with a sprite re-used and re-positioned horizontally! Moving the sprite's position takes almost an entire scanline (76 CPU cycles) and is timing-sensitive, so you have to stuff the next line's data into temporaries while rendering the previous two lines, then blarghh out the next line as quickly as possible. Woe betide you if code or data crosses a page boundary and you get penalized an extra cycle...
Though many of these tricks have been documented on AtariAge.com and similar sites, and some new tricks occasionally trickle out, the problem of 2600 kernel programming hasn't really been "solved" yet -- there isn't yet a compiler that can generate 6502 code for an arbitrary screen, or prove that it can't be done.
(Speaking of Activision pioneers, a couple of them have released a new Atari 2600 game)
posted by RobotVoodooPower at 1:27 PM on June 17, 2021 [3 favorites]
Now try doing two multicolor sprites overlapping a playfield, with a sprite re-used and re-positioned horizontally! Moving the sprite's position takes almost an entire scanline (76 CPU cycles) and is timing-sensitive, so you have to stuff the next line's data into temporaries while rendering the previous two lines, then blarghh out the next line as quickly as possible. Woe betide you if code or data crosses a page boundary and you get penalized an extra cycle...
Though many of these tricks have been documented on AtariAge.com and similar sites, and some new tricks occasionally trickle out, the problem of 2600 kernel programming hasn't really been "solved" yet -- there isn't yet a compiler that can generate 6502 code for an arbitrary screen, or prove that it can't be done.
(Speaking of Activision pioneers, a couple of them have released a new Atari 2600 game)
posted by RobotVoodooPower at 1:27 PM on June 17, 2021 [3 favorites]
My first long grind in a video game was the Raiders of the Lost Ark on the 2600. I remember solving all the puzzles and figuring out how to use the map room. This was 39 years ago.
posted by ShakeyJake at 2:11 PM on June 17, 2021 [7 favorites]
posted by ShakeyJake at 2:11 PM on June 17, 2021 [7 favorites]
“The resolution is 160 by how fast your code is”
posted by acb at 2:15 PM on June 17, 2021 [3 favorites]
posted by acb at 2:15 PM on June 17, 2021 [3 favorites]
I knew they were changing colours and contents of the sprite data per-line, but it's new to me that you can't set a sprite position register earlier in the scan-line, but have to execute a command to set it at the current position of the scanning beam.
So the ET title-screen example is easy mode in one sense, because it has a fixed position on screen. I'm now kind of boggling at the idea that, when you have multiple sprites moving around the screen, that actually changes the order you need to render them.
posted by RobotHero at 4:57 PM on June 17, 2021
So the ET title-screen example is easy mode in one sense, because it has a fixed position on screen. I'm now kind of boggling at the idea that, when you have multiple sprites moving around the screen, that actually changes the order you need to render them.
posted by RobotHero at 4:57 PM on June 17, 2021
The 128 bytes of memory is a little misleading, as it had space in its memory map for 4 KB of ROM that was in the cartridge. I worked on Engine Control Modules with 256 bytes of RAM, 8 KB of software ROM, and a 1 KB calibration PROM in this same timeframe.
posted by rfs at 6:32 PM on June 17, 2021 [5 favorites]
posted by rfs at 6:32 PM on June 17, 2021 [5 favorites]
it's new to me that you can't set a sprite position register earlier in the scan-line, but have to execute a command to set it at the current position of the scanning beam.
It's even worse than that, because 3 pixels fly by for every 1 CPU cycle. So, you have to set the coarse position first (since you can only get within 3 pixels at best) then fine-tune it with another register.
Joe made a routine that made this easy for programmers. Give it a horizontal position, and it'll divide it by 15 via repeated subtraction -- but each iteration of the subtract loop takes 5 CPU cycles, i.e. 15 pixels. So when it's done, you're no more than 15 pixels from where you want to be. The fine-tune register can move +-8 pixels, so you use the X/15 remainder and a little math or lookup table to set it.
If you want to reuse sprites, you do have to draw the objects in the order they appear top-to-bottom. This is easier you can guarantee they won't overlap horizontally -- e.g. River Raid uses the first sprite for the player, and reuses the second sprite for all other objects (which can overlap the player). But if you want to draw them in arbitrary positions, you'll have to implement flicker -- which usually involves a kind of bubble sort iteration each frame.
posted by RobotVoodooPower at 7:17 PM on June 17, 2021 [1 favorite]
It's even worse than that, because 3 pixels fly by for every 1 CPU cycle. So, you have to set the coarse position first (since you can only get within 3 pixels at best) then fine-tune it with another register.
Joe made a routine that made this easy for programmers. Give it a horizontal position, and it'll divide it by 15 via repeated subtraction -- but each iteration of the subtract loop takes 5 CPU cycles, i.e. 15 pixels. So when it's done, you're no more than 15 pixels from where you want to be. The fine-tune register can move +-8 pixels, so you use the X/15 remainder and a little math or lookup table to set it.
If you want to reuse sprites, you do have to draw the objects in the order they appear top-to-bottom. This is easier you can guarantee they won't overlap horizontally -- e.g. River Raid uses the first sprite for the player, and reuses the second sprite for all other objects (which can overlap the player). But if you want to draw them in arbitrary positions, you'll have to implement flicker -- which usually involves a kind of bubble sort iteration each frame.
posted by RobotVoodooPower at 7:17 PM on June 17, 2021 [1 favorite]
« Older UK libraries and museums unite to save... | Juneteenth Becomes a Federal Holiday Newer »
This thread has been archived and is closed to new comments
posted by wierdo at 12:04 PM on June 17, 2021 [2 favorites]