Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 2

CHIP-8 Registers Explained

Recommended resources

Following our initial exploration of the CHIP-8 memory map, we will now zoom in from the system's overall memory structure to the high-speed, internal workspace of its virtual CPU: the registers. Your background in computer architecture means you're already well-acquainted with the fundamental role of registers in program execution. This lesson will focus on the specific set of registers used by the CHIP-8 virtual machine, detailing their sizes, names, and distinct purposes.

Our objective is to identify each CHIP-8 register—the general-purpose V registers, the index register I, the program counter PC, and the stack pointer SP—and understand its specific function. We will pay special attention to the VF register, which serves a dual role as both a data holder and a status flag.

The CHIP-8 CPU Registers: An Overview

At the heart of any processor, virtual or physical, is a set of registers that hold the immediate data and control information needed to execute a program. CHIP-8's set is minimal and simple, which makes it perfect for our study. Let's begin with a concise summary of all the components.

Guide to making a CHIP-8 emulator - Tvil

The guide "Write a CHIP-8 emulator" by Tobias V. Langhoff provides an excellent, clear summary of the CHIP-8's architectural components. This will give us a high-level map of the registers before we examine each one in detail.

Please read the introductory list under the Specifications heading. As you read, take note of the size (e.g., 8-bit or 16-bit) and the one-sentence purpose of each register type.

Now that you have a general overview, let's dissect each component.


General-Purpose Registers: V0 through VF

The core of the CHIP-8's data manipulation capabilities lies in its 16 general-purpose 8-bit registers, denoted V0, V1, ..., VE, VF.

  • These registers are used for storing intermediate values during calculations, much like the general-purpose register file (eax, ebx, etc., in x86, or x0-x31 in RISC-V) in a physical CPU.
  • Most arithmetic and bitwise logical instructions operate on these registers. For example, an instruction might add the value in V1 to the value in V2 and store the result back in V1.
  • Since they are 8-bit, each can hold an unsigned integer value from 0 to 255 (or 0x00 to 0xFF).

The Special Case: VF, the Flag Register

The last register, VF, is unique. While it can be used like any other V register for general data, it has a special purpose: it doubles as a flag register. Many instructions modify VF to signal the outcome of an operation. This is a common design pattern in processor architecture, analogous to the EFLAGS register in x86.

The VF register is used to report:

  1. Carry in addition (8XY4). If an addition results in a value greater than 255 (overflowing the 8-bit register), VF is set to 1; otherwise, it's set to 0.
  2. No Borrow in subtraction (8XY5 and 8XY7). If Vx is greater than or equal to Vy in a Vx - Vy operation, VF is set to 1. If a "borrow" is needed (i.e., Vx < Vy), VF is set to 0.
  3. Shifted-out bit in bit-shift operations (8XY6 and 8XYE). VF is set to the value of the bit that is shifted out of the register (either the least-significant or most-significant bit).
  4. Collision during sprite drawing (DXYN). When a sprite is drawn to the screen, if any of its pixels are flipped from on to off, VF is set to 1 to signal a collision. Otherwise, it's set to 0.

Let's look at a more formal specification to see exactly how certain instructions use VF.

[PDF] Chip-8 Design Specification - Columbia University Computer Science

This formal design specification from Columbia University provides precise, unambiguous descriptions of the CHIP-8 instruction set and the behavior of the VF register.

First, in the "Memory Overview" section, read the final bullet point that concisely describes the VF register's dual function. Next, skim through the "Op Codes" section. You don't need to memorize the opcodes, but focus on the descriptions for the following instructions to see the flag mechanism in action: 8xy4 (ADD) 8xy5 (SUB) 8xy6 (SHR) Notice the pattern: an operation is performed, and VF is set to 1 or 0 to report a specific condition about the result.


Special-Purpose Registers: PC, I, and SP

Beyond the V registers, CHIP-8 has three other crucial registers that manage program flow and memory access. These are 16-bit registers, allowing them to address the entire 4KB (12-bit) memory space.

Program Counter (PC)

The Program Counter is a 16-bit register that holds the memory address of the next instruction to be executed. This is the engine that drives the program forward.

  • As we discussed in the previous lesson, program ROMs are loaded starting at address 0x200. Therefore, the PC is initialized to 0x200 at the start of execution.
  • After fetching an instruction, the PC is typically incremented by 2 (since each instruction is 2 bytes long) to point to the next one in sequence.
  • Control flow instructions, such as jumps (1NNN) and subroutine calls (2NNN), directly modify the PC to change the flow of execution.

Index Register (I)

The Index Register is a 16-bit register used to store a memory address. It acts as a general-purpose pointer, typically used to reference data within memory. Its primary uses are:

  • To point to the location of sprite data in memory for the draw instruction (DXYN).
  • To point to the location of font characters (FX29).
  • To serve as a base address for saving (FX55) or loading (FX65) the contents of V registers to/from memory.

The Stack and the Stack Pointer (SP)

CHIP-8 has a mechanism for handling subroutines. To do this, it needs a stack, which is a LIFO (Last-In, First-Out) data structure used to store return addresses.

  • The Stack Pointer (SP) is an 8-bit register that points to the top of the stack.
  • When a subroutine is called (2NNN), the interpreter pushes the current value of the PC onto the stack and then increments the SP. The PC is then set to the subroutine's address.
  • When a subroutine returns (00EE), the interpreter decrements the SP and then pops the address from the top of the stack back into the PC, resuming execution where it left off.

This interaction between the PC and the stack is a fundamental concept in procedural programming.

[PDF] Chip-8 Design Specification - Columbia University Computer Science

Let's refer back to the specification to see the formal descriptions of the subroutine instructions.

In the "Op Codes" section of the same PDF, find the entries for 00EE - RET (Return) and 2nnn - CALL (Call subroutine). Observe how these two instructions explicitly describe the manipulation of the stack, the stack pointer, and the program counter to manage function calls.


Visualizing the Registers

Seeing these registers in the context of a running program makes their roles much clearer. The image below is a screenshot from a CHIP-8 emulator with a debugger, showing the state of the machine at a particular moment.

A snapshot of a CHIP-8 emulator. On the right, you can see the current state of all the registers. The 16 general-purpose registers (`V0`-`VF`) are listed, along with the special-purpose `PC`, `I`, and `SP`. Notice their hexadecimal values, representing the machine's state at this point in the program's execution.

As you can see, all the registers we've discussed are laid out for inspection. This kind of debugging view will be invaluable as you build and test your own emulator.


From Theory to JavaScript

Ultimately, we will need to represent this virtual hardware in our JavaScript code. The following video segment shows how one developer approaches this task, mapping these architectural concepts to a concrete data structure.

Building and understanding a Virtual Machine in 2hrs (CHIP-8 Emulator)

To bridge the gap between this theory and our implementation goal, watch this segment from the video "Building and understanding a Virtual Machine in 2hrs" by Ankush.

Watch the section from designing the data structure. The presenter discusses how to create a JavaScript class to represent the CHIP-8 machine. Pay close attention to how he decides to implement the memory, the V registers (this.v), the index register (this.index), the program counter (this.pc), and the stack (this.stack). This provides a practical first look at the code structure we will soon be building.


Conclusion

In this lesson, we have itemized and described the full register set of the CHIP-8 virtual CPU. These registers are the core working parts of the machine, enabling everything from simple arithmetic to program control flow and graphics.

Key takeaways from today's lesson:

  • General-Purpose Registers (V0-VF): 16 registers, each 8 bits wide, used for data manipulation.
  • Flag Register (VF): The 16th V register, which also serves to report conditions like arithmetic carry, borrow, and sprite collision.
  • Program Counter (PC): A 16-bit register that points to the next instruction in memory, starting at 0x200.
  • Index Register (I): A 16-bit register used as a pointer to addresses in memory, often for data- and graphics-related operations.
  • Stack Pointer (SP): A register used to manage the stack for subroutine calls and returns.

With our understanding of both the memory layout and the CPU registers, we are getting closer to having a complete blueprint of the CHIP-8 machine. In the next lesson, we will focus on a specific piece of data that lives in the reserved area of memory: the built-in font set. You'll learn how these simple sprites are stored and how they are accessed using the I register we discussed today.