Open main menu
Home
Random
Recent changes
Special pages
Community portal
Preferences
About Wikipedia
Disclaimers
Incubator escapee wiki
Search
User menu
Talk
Dark mode
Contributions
Create account
Log in
Editing
CHIP-8
(section)
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
==Virtual machine description== ===Memory=== CHIP-8 was most commonly implemented on 4K systems, such as the Cosmac VIP and the Telmac 1800. These machines had 4096 (0x1000) memory locations, all of which are 8 bits (a [[byte]]) which is where the term CHIP-8 originated. However, the CHIP-8 interpreter itself occupies the first 512 bytes of the memory space on these machines. For this reason, most programs written for the original system begin at memory location 512 (0x200) and do not access any of the memory below the location 512 (0x200). The uppermost 256 bytes (0xF00-0xFFF) are reserved for display refresh, and the 96 bytes below that (0xEA0-0xEFF) were reserved for the call stack, internal use, and other variables. In modern CHIP-8 implementations, where the interpreter is running natively outside the 4K memory space, there is no need to avoid the lower 512 bytes of memory (0x000-0x1FF), and it is common to store font data there. ===Registers=== CHIP-8 has 16 8-[[bit]] data [[processor register|registers]] named V0 to VF. The VF register doubles as a flag for some instructions; thus, it should be avoided. In an addition operation, VF is the [[Status register|carry flag]], while in subtraction, it is the "no borrow" flag. In the draw instruction VF is set upon pixel collision. The address register, which is named I, is 12 bits wide and is used with several [[opcode]]s that involve memory operations. ===The stack=== The [[call stack|stack]] is only used to store return addresses when [[subroutine]]s are called. The original [[RCA 1802]] version allocated 48 bytes for up to 12 levels of nesting;<ref>{{Cite book|url=https://archive.org/details/bitsavers_rcacosmacCManual1978_6956559/page/n36/mode/2up|title=RCA COSMAC VIP CDP18S711 Instruction Manual|publisher=RCA Solid State Division|year=1978|location=Somerville|pages=36}}</ref> modern implementations usually have more.<ref>{{Cite web |last=Greene |first=Thomas P. |date=1997-08-30 |title=Cowgod's Chip-8 Technical Reference |url=http://devernay.free.fr/hacks/chip8/C8TECH10.HTM |url-status=live |archive-url=https://web.archive.org/web/20240103155311/http://devernay.free.fr/hacks/chip8/C8TECH10.HTM |archive-date=2024-01-03 |access-date=2020-02-03 |website=devernay.free.fr }}</ref><ref>{{Cite web|url=http://mattmik.com/files/chip8/mastering/chip8.html|title=Mastering CHIP-8 : Subroutines|last=Mikolay|first=Matthew|website=mattmik.com|access-date=2020-02-03}}</ref> ===Timers=== CHIP-8 has two timers. They both count down at 60 [[hertz]], until they reach 0. *Delay timer: This timer is intended to be used for timing the events of games. Its value can be set and read. *Sound timer: This timer is used for sound effects. When its value is nonzero, a beeping sound is made. Its value can only be set. ===Input=== Input is done with a [[hexadecimal|hex]] [[computer keyboard|keyboard]] that has 16 keys ranging 0 to F. The '8', '4', '6', and '2' keys are typically used for directional input. Three opcodes are used to detect input. One skips an instruction if a specific key is pressed, while another does the same if a specific key is ''not'' pressed. The third waits for a key press, and then stores it in one of the data registers. ===Graphics and sound=== Original CHIP-8 [[display resolution]] is 64×32 [[pixel]]s, and color is [[monochrome]]. Graphics are drawn to the screen solely by drawing [[sprite (computer science)|sprite]]s, which are 8 pixels wide and may be from 1 to 15 pixels in height. Sprite pixels are [[XOR]]'d with corresponding screen pixels. In other words, sprite pixels that are set flip the color of the corresponding screen pixel, while unset sprite pixels do nothing. The carry flag (VF) is set to 1 if any screen pixels are flipped from set to unset when a sprite is drawn and set to 0 otherwise. This is used for collision detection. As previously described, a beeping sound is played when the value of the sound timer is nonzero. ===Opcode table=== CHIP-8 has 35 [[opcode]]s, which are all two bytes long and stored [[Endianness|big-endian]]. The opcodes are listed below, in hexadecimal and with the following symbols: *NNN: address *NN: 8-bit constant *N: 4-bit constant *X and Y: 4-bit register identifier *PC : Program Counter *I : 12bit register (For memory address) (Similar to void pointer); *VN: One of the 16 available variables. N may be 0 to F (hexadecimal); There have been many implementations of the CHIP-8 instruction set since 1978. The following specification is based on the SUPER-CHIP specification from 1991 (but without the additional opcodes that provide extended functionality), as that is the most commonly encountered extension set today. Footnotes denote incompatibilities with the original CHIP-8 instruction set from 1978. {| class="wikitable sortable" !Opcode !Type !C Pseudocode !Explanation |- | {{mono|0NNN}} | {{mono|Call}} | |Calls machine code routine ([[RCA 1802]] for COSMAC VIP) at address NNN. Not necessary for most ROMs.<ref name=":0" /> |- | {{mono|00E0}} | {{mono|Display}} | {{code|1=disp_clear()|2=c}} |Clears the screen.<ref name=":0">{{Cite web |last=Schümann |first=Steffen "Gulrak" |title=CHIP-8 Variant Opcode Table |url=https://chip8.gulrak.net/ |website=chip8.gulrak.net}}</ref> |- | {{mono|00EE}} | {{mono|Flow}} | {{code|1=return;|2=c}} |Returns from a subroutine.<ref name=":0" /> |- | {{mono|1NNN}} | {{mono|Flow}} | {{code|1=goto NNN;|2=c}} |Jumps to address NNN.<ref name=":0" /> |- | {{mono|2NNN}} | {{mono|Flow}} | {{code|1=*(0xNNN)()|2=c}} |Calls subroutine at NNN.<ref name=":0" /> |- | {{mono|3XNN}} | {{mono|Cond}} | {{code|1=if (Vx == NN)|2=c}} |Skips the next instruction if VX equals NN (usually the next instruction is a jump to skip a code block).<ref name=":0" /> |- | {{mono|4XNN}} | {{mono|Cond}} | {{code|1=if (Vx != NN)|2=c}} |Skips the next instruction if VX does not equal NN (usually the next instruction is a jump to skip a code block).<ref name=":0" /> |- | {{mono|5XY0}} | {{mono|Cond}} | {{code|1=if (Vx == Vy)|2=c}} |Skips the next instruction if VX equals VY (usually the next instruction is a jump to skip a code block).<ref name=":0" /> |- | {{mono|6XNN}} | {{mono|Const}} | {{code|1=Vx = NN|2=c}} |Sets VX to NN.<ref name=":0" /> |- | {{mono|7XNN}} | {{mono|Const}} | {{code|1=Vx += NN|2=c}} |Adds NN to VX (carry flag is not changed).<ref name=":0" /> |- | {{mono|8XY0}} | {{mono|Assig}} | {{code|1=Vx = Vy|2=c}} |Sets VX to the value of VY.<ref name=":0" /> |- | {{mono|8XY1}} | {{mono|BitOp}} | <syntaxhighlight lang="c" inline>Vx |= Vy</syntaxhighlight> |Sets VX to VX [[Logical disjunction|or]] VY. (bitwise OR operation).<ref name=":0" /> |- | {{mono|8XY2}} | {{mono|BitOp}} | {{code|1=Vx &= Vy|2=c}} |Sets VX to VX [[Logical conjunction|and]] VY. (bitwise AND operation).<ref name=":0" /> |- | {{mono|8XY3}}{{efn|name=rcaops|The logical opcodes 8XY3, 8XY6, 8XY7 and 8XYE were not documented in the original CHIP-8 specification, as all the 8000 opcodes were dispatched to instructions in the 1802's [[Arithmetic logic unit|ALU]], and not located in the interpreter itself; these four additional opcodes were therefore presumably unintentional functionality.}} | {{mono|BitOp}} | {{code|1=Vx ^= Vy|2=c}} |Sets VX to VX [[xor]] VY.<ref name=":0" /> |- | {{mono|8XY4}} | {{mono|Math}} | {{code|1=Vx += Vy|2=c}} |Adds VY to VX. VF is set to 1 when there's an overflow, and to 0 when there is not.<ref name=":0" /> |- | {{mono|8XY5}} | {{mono|Math}} | {{code|1=Vx -= Vy|2=c}} |VY is subtracted from VX. VF is set to 0 when there's an underflow, and 1 when there is not. (i.e. VF set to 1 if VX >= VY and 0 if not).<ref name=":0" /> |- | {{mono|8XY6}}{{efn|name=rcaops}} | {{mono|BitOp}} | {{code|1=Vx >>= 1|2=c}} |Shifts VX to the right by 1, then stores the least significant bit of VX prior to the shift into VF.{{efn|name=bitshift|CHIP-8's opcodes 8XY6 and 8XYE (the bit shift instructions), which were in fact undocumented opcodes in the original interpreter, shifted the value in the register VY and stored the result in VX. The CHIP-48 and SCHIP implementations instead ignored VY, and simply shifted VX.{{refn|name=compatibility}}}}<ref name=":0" /> |- | {{mono|8XY7}}{{efn|name=rcaops}} | {{mono|Math}} | {{code|1=Vx = Vy - Vx|2=c}} |Sets VX to VY minus VX. VF is set to 0 when there's an underflow, and 1 when there is not. (i.e. VF set to 1 if VY >= VX).<ref name=":0" /> |- | {{mono|8XYE}}{{efn|name=rcaops}} | {{mono|BitOp}} | {{code|1=Vx <<= 1|2=c}} |Shifts VX to the left by 1, then sets VF to 1 if the most significant bit of VX prior to that shift was set, or to 0 if it was unset.{{efn|name=bitshift}}<ref name=":0" /> |- | {{mono|9XY0}} | {{mono|Cond}} | {{code|1=if (Vx != Vy)|2=c}} |Skips the next instruction if VX does not equal VY. (Usually the next instruction is a jump to skip a code block).<ref name=":0" /> |- | {{mono|ANNN}} | {{mono|MEM}} | {{code|1=I = NNN|2=c}} |Sets I to the address NNN.<ref name=":0" /> |- | {{mono|BNNN}} | {{mono|Flow}} | {{code|1=PC = V0 + NNN|2=c}} |Jumps to the address NNN plus V0.<ref name=":0" /> |- | {{mono|CXNN}} | {{mono|Rand}} | {{code|1=Vx = rand() & NN|2=c}} |Sets VX to the result of a bitwise and operation on a random number (Typically: 0 to 255) and NN.<ref name=":0" /> |- | {{mono|DXYN}} | {{mono|Display}} | {{code|1=draw(Vx, Vy, N)|2=c}} |Draws a sprite at coordinate (VX, VY) that has a width of 8 pixels and a height of N pixels. Each row of 8 pixels is read as bit-coded starting from memory location I; I value does not change after the execution of this instruction. As described above, VF is set to 1 if any screen pixels are flipped from set to unset when the sprite is drawn, and to 0 if that does not happen.<ref name=":0" /> |- | {{mono|EX9E}} | {{mono|KeyOp}} | {{code|1=if (key() == Vx)|2=c}} |Skips the next instruction if the key stored in VX(only consider the lowest nibble) is pressed (usually the next instruction is a jump to skip a code block).<ref name=":0" /> |- | {{mono|EXA1}} | {{mono|KeyOp}} | {{code|1=if (key() != Vx)|2=c}} |Skips the next instruction if the key stored in VX(only consider the lowest nibble) is not pressed (usually the next instruction is a jump to skip a code block).<ref name=":0" /> |- | {{mono|FX07}} | {{mono|Timer}} | {{code|1=Vx = get_delay()|2=c}} |Sets VX to the value of the delay timer.<ref name=":0" /> |- | {{mono|FX0A}} | {{mono|KeyOp}} | {{code|1=Vx = get_key()|2=c}} |A key press is awaited, and then stored in VX (blocking operation, all instruction halted until next key event, delay and sound timers should continue processing).<ref name=":0" /> |- | {{mono|FX15}} | {{mono|Timer}} | {{code|1=delay_timer(Vx)|2=c}} |Sets the delay timer to VX.<ref name=":0" /> |- | {{mono|FX18}} | {{mono|Sound}} | {{code|1=sound_timer(Vx)|2=c}} |Sets the sound timer to VX.<ref name=":0" /> |- | {{mono|FX1E}} | {{mono|MEM}} | {{code|1=I += Vx|2=c}} |Adds VX to I. VF is not affected.{{efn|Most CHIP-8 interpreters' FX1E instructions do not affect VF, with one exception: the CHIP-8 interpreter for the Commodore Amiga sets VF to 1 when there is a range overflow (I+VX>0xFFF), and to 0 when there is not.<ref>{{cite web |url=https://github.com/Chromatophore/HP48-Superchip/issues/2 |title = FX1E and VF · Issue #2 · Chromatophore/HP48-Superchip · GitHub| website=[[GitHub]] }}</ref> The only known game that depends on this behavior is Spacefight 2091!, while at least one game, Animal Race, depends on VF not being affected.}}<ref name=":0" /> |- | {{mono|FX29}} | {{mono|MEM}} | {{code|1=I = sprite_addr[Vx]|2=c}} |Sets I to the location of the sprite for the character in VX(only consider the lowest nibble). Characters 0-F (in hexadecimal) are represented by a 4x5 font.<ref name=":0" /> |- | {{mono|FX33}} | {{mono|BCD}} | <syntaxhighlight lang="c" style="font-size: 90%">set_BCD(Vx) *(I+0) = BCD(3); *(I+1) = BCD(2); *(I+2) = BCD(1);</syntaxhighlight> |Stores the [[binary-coded decimal]] representation of VX, with the hundreds digit in memory at location in I, the tens digit at location I+1, and the ones digit at location I+2.<ref name=":0" /> |- | {{mono|FX55}} | {{mono|MEM}} | {{code|1=reg_dump(Vx, &I)|2=c}} |Stores from V0 to VX (including VX) in memory, starting at address I. The offset from I is increased by 1 for each value written, but I itself is left unmodified.{{efn|name=increment|In the original CHIP-8 implementation, and also in CHIP-48, I is left incremented after this instruction had been executed. In SCHIP, I is left unmodified.}}<ref name=":0" /> |- | {{mono|FX65}} | {{mono|MEM}} | {{nowrap|{{code|1=reg_load(Vx, &I)|2=c}}}} |Fills from V0 to VX (including VX) with values from memory, starting at address I. The offset from I is increased by 1 for each value read, but I itself is left unmodified.{{efn|name=increment}}<ref name=":0" /> |}
Edit summary
(Briefly describe your changes)
By publishing changes, you agree to the
Terms of Use
, and you irrevocably agree to release your contribution under the
CC BY-SA 4.0 License
and the
GFDL
. You agree that a hyperlink or URL is sufficient attribution under the Creative Commons license.
Cancel
Editing help
(opens in new window)