skip navigation

How the ATARI 2600 Responds to Joysticks and Switches


In this episode we explore how to read input from cx-40 joystick controllers and the console switches

March 26, 2022

Original Link:


Your support is greatly appreciated!

This is 8Blit a channel teaching you everything you need to know to make games for the 8-bit atari 2600 in this episode we’ll explore how to control our player and respond to the console switches for both six-switch and four-switch models. There’s lots to cover here and lots of examples for you to try yourself so let’s get started.

When the Atari 2600 was first released it came packaged with two sets of remote controllers consisting of two cx-30 paddle controllers and two cx-10 joystick controllers, later to be replaced with the cost reduced cx-40 model. The joystick controller consists of a single switch for the button and four switches for up down left and right the internal design of the joystick would enable two switches to be engaged at the same time allowing for eight directions of movement. Each joystick used up one of the two available joystick ports on the console.

The paddle controllers also have a single button located on the left side of the base, and a potentiometer that can rotate approximately 330 degrees by turning the dial on the top. Unlike the joysticks, both paddles are used with a single port allowing the console to handle up to four paddle controllers at the same time.

A few other controllers were also released for the 2600 like the cx-50 keyboard controller which was sold in pairs, each consisting of 12 buttons the controllers could slide together for combined 24 buttons and allowed overlays to be put on top to indicate which function each button performed within the game. However, only a handful of games were made for it. Not to be outdone the cx-20 driving controller only had a single game officially released for it the driving controller had a very similar look and feel to the cx-30 paddle controller. However, it swaps the paddle’s potentiometer for a rotary encoder allowing a continuous 360 degrees of rotation, and each controller required its own port. It was packaged along with indy 500 a two-player game where you race around various tracks in several play modes. I remember that being a really fun game but I don’t know why other publishers didn’t create games for the driving controller. If you remember playing Indy 500 let me know what you thought about it in the comments.

All these different controllers use the same type of port to connect to the Atari console the DE-9 port was first introduced by canon in 1952. ‘D’ refers to the shape of the connection, ‘E’ refers to the size and ‘9’ for the number of pins it contains. The pins are laid out in two rows with five on the top and four on the bottom. This connection became the Atari standard and would be used for the entire 8-bit family of Atari computers, the Atari 7800 and the Atari ST. Other manufacturers took note of the popularity of the port and the number of existing controllers on the market and decided to use the same connection for their products. This can be seen in the Commodore Vic-20, Commodore 64, Colecovision, Commodore Amiga, Sega Master System, Sega Genesis, and more. While the connector stayed the same manufacturers started pushing the limits and adding more buttons and features to their controllers which started to break compatibility across platforms. Over time the game port began taking over on computers and is now replaced with either USB or Bluetooth controllers.

While the joystick and paddle controllers allow your player to interact within its own game world there are a few more switches available to use to set up this world. When the Atari 2600 first came out it featured six switches on its front panel. In fact, these days the first version of the 2600 is often referred to as a ‘heavy sixer’. ‘heavy’, because it contained thicker material for its body construction as well as a heavy RF shield inside the console, and ‘sixer’ is referring to the number of switches. A cost-reduced version came out in 1978 which decreased the weight and thickness of the body this would become known as the ‘light sixer’. The control panel’s six switches consisted of an on/off power switch, a TV Type switch to change between color and black and white modes, two difficulty switches that could set a difficulty level of A or B for each player, game select to change which level or board you want to play, and finally a game reset switch which is used to exit your current game and return to the beginning. Two years after the release of the light sixer came the four switch models which moved the two difficulty switches to the back and left the power, tv type, game select, and game reset. Whatever label we place on these switches it’s really up to you to do what you want to do with them. All except for the power switch which physically turns the power on or off. The other switches are all controlled through software even the game reset switch. The tv type switch to change between color and black and white what that does is up to you, there’s no hardware that changes the video output between color and black and white and the only reason the switch exists is to allow the game developer to switch to a palette that looks better when viewed on the black and white television which were still very common at the time.

Best not to stray too far from their original intention of each switch or you may risk confusing players. However many games use the switches in interesting ways. Star Voyager uses the game reset to start your game, right difficulty controls your weapon choice, while left difficulty changes the speed of certain in-game mechanics. F-14 used reset to start the game, game select to cycle through computer display screens, right difficulty raises or lowers the arresting hook, and left difficulty raises or lowers the landing gear. It even features protection from accidentally hitting reset in what it calls ‘intelligent reset’ which will only reset the game back to the start if you hold it down for at least two seconds.

The Atari 2600 contains two 8-bit parallel IO ports which are part of the 6532 peripheral interface adapter or PIA for short. This is not to be confused with the two joystick ports on the console. These IO ports are internal. However, their function is to monitor the joystick and console switches and provide us with an interface from which we can read their state.

The two IO ports are referred to as port A and port B. Port A which handles the controllers has an 8-bit wide Data Direction Register or DDR capable of setting each individual pin to either input or output. To my knowledge, a feature is only used with the cx-50 keyboard controller. Port B is used exclusively for reading the console switches and the port is actually hardwired to only handle input when the data direction register has set the port A pins for input. Then we can read these pins using the one-byte SWCHA address this one register handles all the motion controls for a joystick controller. The data bits are laid out as follows. Player 0 uses the top nibble. Whereas d7 is right, d6 is left, d5 is down and d4 is up. The bottom nibble is used for player 1. Whereas d3 is right, d2 is left, d1 is down, and d0 is up. When the player moves the joystick and engages a switch, the corresponding bit will go low as represented with a value of 0. If a switch is not currently engaged the bit will contain a value of 1. Complementary to the SWCHA address we also have a series of six input port addresses four of these are called dumped ports which are used by the paddle controllers to determine movement. I think the paddle controllers deserve their own episode so we’ll be covering them at some point in the future. For now, we’ll stick with handling joysticks which are the other two input addresses and they can be used to determine if the joystick buttons have been pressed.

INPT4 handles player 0, while INPT5 for player 1. We can check for a button press by reading d7 of each port. When a button is not pressed d7 is one. When the button is pressed then d7 will go to zero. INPT4 and INT5 are both latching ports which means they can retain their status until they are cleared. You can enable latching by writing a 1 to d6 a VBLANK or a 0 to disable. When enabled a button press will set d7 to 0 and remain that way even when you release the button. When disabled, d7 would immediately return to 1 when the button is released. This is useful when you want to make sure you capture a button press. When latching is off and you’re not checking for button presses often there could be a chance the button press was between checks which would result in losing the user’s input and makes the game feel laggy and unresponsive. When latching is on you will always catch a button press that occurred between checks. However, if you’re checking input every frame or every few frames then this is maybe unnecessary.

Let’s bring up this episode’s example code as always it’s available on our GITHUB and I’ll leave a link in this episode’s description. First, let’s have a look at detecting and responding to a button press in this bit of code. I want to change the color for the player graphic when the joystick button is pressed. We’re storing the color value of the data table stored at the ghost color pointer. An index of 0 will be our normal yellow ghost while an index of 1 will be a red ghost. First, we load the Y register with a 0 which will be our normal ghost color then we’ll use the BIT instruction along with the INPT4 address. In this case, we’re using BIT to check d7 of INPT4. If d7 is set then the BIT instruction will set the N (or negative) processor status flag. All we have to do now is use the branch if minus instruction to check if the bit was pressed. If it was then we’ll change the Y register to use the color index 2 of our ghost color register. Then we’ll pull the color value and set the player 1 color playing the example code. We can see the ghost is normally yellow but changes to red when we press the joystick button.

Now let’s have a look at reading directional input looking at the code that handles when the right joystick switch is depressed. We first start with loading the current player’s horizontal position into the X register then loading a byte into the accumulator with d7 set. This as we’ve previously mentioned is the bit for player zero’s right switch. We’ll then use the BIT instruction again with the memory address for SWCHA A. In this context, it’s going to perform an AND on the accumulator and set the processor status Z (Zero) flag depending if d7 is set or not. If the Z flag is set then we know the joystick’s right switch is depressed. In that case, we’ll compare our current horizontal position to the maximum horizontal position. If we’re not yet reached the maximum then we’ll increase it by one. Since we know our player is moving to the right we’re going to turn on reflect for our player graphics so the graphic looks like it’s facing to the right. We’ll turn off reflect when we detect left movement. That’s basically all there is to it handling left up and down are pretty much handled in the same way. You can refer to the example code for the exact implementation. When we execute the code we can move our ghost all around the screen and he flips to face in the direction he’s moving

The Atari 2600 also features either four or six switches on the console. All these switches are readable from the SWCHB address with the bits representing the state of the switches. d0 handles reset, d1 game select, d3 color or black and white, while d6 and d7 handle the player zero and one difficulty. Let’s have a look at how we can implement the tv type switch. As mentioned previously the switch options are labeled color and black and white but you can implement this switch any way you’d like. For now, we’re going to stick with the original intention for the switch. First, we’ll need to define an alternate color palette and create our pointer so we can pull the palette we want to use with an index. The values we’re using are just different shades of gray to approximate the contrast between the different hues and luminosities in our normal color palette. Now we’ll set the default to be the colored palette which is index 0. Then we check d3 using the BIT instruction. If the switch is set to black and white then the Z flag will be 0, and our branch will continue to the next lines, setting the palette index to 1 which is our black and white palette. We then set the shade for the ghost color pointer of which the first two colors will be used for the player graphic when the joystick button is pressed or not. The next two shades will be used for the background color and the playfield color. The player difficulty switches work in the exact same way using d7 and d6 for player 0 and player 1, and when we switch the tv type it looks like this.

The game select switch is an interesting one. It’s a momentary toggle switch that will spring back up after being pulled down. This actually introduces a problem since the switch is usually used to move through a list of possible values. For instance, which level you want to play. You don’t want to act on it too fast. If you’re reading this input 60 times a second there’s a good chance the player will hold the switch down longer than 1/60th of a second. If that happens then it would be hard to accurately choose the stage you want if it switches that fast to handle this. After detecting a state change we need to introduce a delay before we read the input again. In electronics, we would call this ‘debouncing’. A way to limit mechanical switch bounces from inadvertently introducing extra unwanted input signals. For this switch we create three new variables ‘select mode’ to determine if we’ll display the background color as stripes or solid, ‘select debounce time’ to use as a delay counter and ‘select debounce on’ to determine if we’re currently debouncing. In our input routine, we’ll first check if we’re currently in debounce. If we’re not then we’ll check d1 of the BIT instruction. If we detect the select switch was depressed then we’ll turn on debounce and set the debounce time to 40 frames. Next, we’ll change the game mode we’re currently in. When we set up the game we loaded alternating bits into the ‘game select’ variable. Now we’ll shift those bits to the left. If that results in the processor status carry flag being cleared then we’ll branch down and set all the playfield pixels to zero. If it was not cleared then we’ll increase the ‘select mode’ variable by one which will return it to a proper alternating pattern of bits and then set the playfield to a striped pattern. That looks a little something like this.

‘Game Reset’ is also a momentary toggle switch but unlike the ‘game select’ switch we don’t really need to retain any state or perform any logic. We simply check if d0 is set, and if so, then we jump execution to the memory address of our ‘reset’ label which is all the way up at the top. It’s here when we first initialize the properties of our game when we depress the switch it looks like this.

With all the information packed into this episode, we’ve really only covered about half there is to know about controllers and inputs. We haven’t covered how to read the keyboard or the paddle and driving controllers. I promise we’ll examine those in the future. Join us on social media. You can connect with us on Instagram Facebook and occasionally on Twitter. If you found this video interesting I’d appreciate it if you’d hit that LIKE button and SHARE this episode to help build the channel. If you haven’t already done so please consider subscribing to the channel and hit the BELL to make sure you’re notified when a new video comes out. If you’d like to help support the development of the channel please consider becoming a PATRON. I’ll link to that in the description as well.

That’s all for now, thanks for watching and I’ll catch you later.

Back to top of page