generated from sigonasr2/CPlusPlusProjectTemplate
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1614 lines
85 KiB
1614 lines
85 KiB
2 years ago
|
<html class=" js " lang="en"><head>
|
||
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8"><style>
|
||
|
.utterances {
|
||
|
position: relative;
|
||
|
box-sizing: border-box;
|
||
|
width: 100%;
|
||
|
max-width: 760px;
|
||
|
margin-left: auto;
|
||
|
margin-right: auto;
|
||
|
}
|
||
|
.utterances-frame {
|
||
|
color-scheme: light;
|
||
|
position: absolute;
|
||
|
left: 0;
|
||
|
right: 0;
|
||
|
width: 1px;
|
||
|
min-width: 100%;
|
||
|
max-width: 100%;
|
||
|
height: 100%;
|
||
|
border: 0;
|
||
|
}
|
||
|
</style>
|
||
|
<meta charset="utf-8">
|
||
|
|
||
|
<!-- begin _includes/seo.html --><title>Guide to making a CHIP-8 emulator - Tobias V. Langhoff</title>
|
||
|
<meta name="description" content="A high-level guide to making a CHIP-8 emulator.">
|
||
|
|
||
|
|
||
|
<meta name="author" content="Tobias V. Langhoff">
|
||
|
|
||
|
<meta property="article:author" content="Tobias V. Langhoff">
|
||
|
|
||
|
|
||
|
|
||
|
<meta property="og:type" content="article">
|
||
|
<meta property="og:locale" content="en_US">
|
||
|
<meta property="og:site_name" content="Tobias V. Langhoff">
|
||
|
<meta property="og:title" content="Guide to making a CHIP-8 emulator">
|
||
|
<meta property="og:url" content="https://tobiasvl.github.io/blog/write-a-chip-8-emulator/">
|
||
|
|
||
|
|
||
|
<meta property="og:description" content="A high-level guide to making a CHIP-8 emulator.">
|
||
|
|
||
|
|
||
|
|
||
|
<meta property="og:image" content="https://tobiasvl.github.io/assets/images/cosmac-vip-manual.png">
|
||
|
|
||
|
|
||
|
|
||
|
<meta name="twitter:site" content="@Spug">
|
||
|
<meta name="twitter:title" content="Guide to making a CHIP-8 emulator">
|
||
|
<meta name="twitter:description" content="A high-level guide to making a CHIP-8 emulator.">
|
||
|
<meta name="twitter:url" content="https://tobiasvl.github.io/blog/write-a-chip-8-emulator/">
|
||
|
|
||
|
|
||
|
<meta name="twitter:card" content="summary_large_image">
|
||
|
<meta name="twitter:image" content="https://tobiasvl.github.io/assets/images/cosmac-vip-manual.png">
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<meta property="article:published_time" content="2020-07-20T00:00:00+00:00">
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<link rel="canonical" href="https://tobiasvl.github.io/blog/write-a-chip-8-emulator/">
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<script type="text/javascript" async="" src="Guide%20to%20making%20a%20CHIP-8%20emulator%20-%20Tobias%20V_files/analytics.js"></script><script type="application/ld+json">
|
||
|
{
|
||
|
"@context": "https://schema.org",
|
||
|
|
||
|
"@type": "Person",
|
||
|
"name": null,
|
||
|
"url": "https://tobiasvl.github.io/",
|
||
|
"sameAs": ["https://twitter.com/Spug","https://github.com/tobiasvl","https://tobiasvl.itch.io","https://instagram.com/spugster"]
|
||
|
|
||
|
}
|
||
|
</script>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<!-- end _includes/seo.html -->
|
||
|
|
||
|
|
||
|
|
||
|
<link href="https://tobiasvl.github.io/feed.xml" type="application/atom+xml" rel="alternate" title="Tobias V. Langhoff Feed">
|
||
|
|
||
|
|
||
|
<!-- https://t.co/dKP3o1e -->
|
||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
|
|
||
|
<script>
|
||
|
document.documentElement.className = document.documentElement.className.replace(/\bno-js\b/g, '') + ' js ';
|
||
|
</script>
|
||
|
|
||
|
<!-- For all browsers -->
|
||
|
<link rel="stylesheet" href="Guide%20to%20making%20a%20CHIP-8%20emulator%20-%20Tobias%20V_files/main.css">
|
||
|
<link rel="stylesheet" href="Guide%20to%20making%20a%20CHIP-8%20emulator%20-%20Tobias%20V_files/all.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||
|
<noscript><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5/css/all.min.css"></noscript>
|
||
|
|
||
|
|
||
|
|
||
|
<!-- start custom head snippets -->
|
||
|
|
||
|
<!-- insert favicons. use https://realfavicongenerator.net/ -->
|
||
|
|
||
|
<!-- end custom head snippets -->
|
||
|
|
||
|
<style id="fit-vids-style">.fluid-width-video-wrapper{width:100%;position:relative;padding:0;}.fluid-width-video-wrapper iframe,.fluid-width-video-wrapper object,.fluid-width-video-wrapper embed {position:absolute;top:0;left:0;width:100%;height:100%;}</style></head>
|
||
|
|
||
|
|
||
|
|
||
|
<body class="layout--single ">
|
||
|
<nav class="skip-links">
|
||
|
<ul>
|
||
|
<li><a href="#site-nav" class="screen-reader-shortcut">Skip to primary navigation</a></li>
|
||
|
<li><a href="#main" class="screen-reader-shortcut">Skip to content</a></li>
|
||
|
<li><a href="#footer" class="screen-reader-shortcut">Skip to footer</a></li>
|
||
|
</ul>
|
||
|
</nav>
|
||
|
|
||
|
<!--[if lt IE 9]>
|
||
|
<div class="notice--danger align-center" style="margin: 0;">You are using an <strong>outdated</strong> browser. Please <a href="https://browsehappy.com/">upgrade your browser</a> to improve your experience.</div>
|
||
|
<![endif]-->
|
||
|
|
||
|
|
||
|
|
||
|
<div class="masthead">
|
||
|
<div class="masthead__inner-wrap">
|
||
|
<div class="masthead__menu">
|
||
|
<nav id="site-nav" class="greedy-nav">
|
||
|
|
||
|
<a class="site-title" href="https://tobiasvl.github.io/">
|
||
|
Tobias V. Langhoff
|
||
|
|
||
|
</a>
|
||
|
<ul class="visible-links"><li class="masthead__menu-item">
|
||
|
<a href="https://tobiasvl.github.io/posts/">Posts</a>
|
||
|
</li><li class="masthead__menu-item">
|
||
|
<a href="https://tobiasvl.github.io/tags/">Tags</a>
|
||
|
</li><li class="masthead__menu-item">
|
||
|
<a href="https://tobiasvl.github.io/about/">About</a>
|
||
|
</li></ul>
|
||
|
|
||
|
<button class="search__toggle" type="button">
|
||
|
<span class="visually-hidden">Toggle search</span>
|
||
|
<i class="fas fa-search"></i>
|
||
|
</button>
|
||
|
|
||
|
<button class="greedy-nav__toggle hidden" type="button" count="0" style="">
|
||
|
<span class="visually-hidden">Toggle menu</span>
|
||
|
<div class="navicon"></div>
|
||
|
</button>
|
||
|
<ul class="hidden-links hidden"></ul>
|
||
|
</nav>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
|
||
|
<div class="initial-content">
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<div id="main" role="main">
|
||
|
|
||
|
<div class="sidebar sticky">
|
||
|
|
||
|
|
||
|
|
||
|
<div itemscope="" itemtype="https://schema.org/Person">
|
||
|
|
||
|
|
||
|
<div class="author__avatar">
|
||
|
|
||
|
<img src="Guide%20to%20making%20a%20CHIP-8%20emulator%20-%20Tobias%20V_files/tvl-photo.jpg" alt="Tobias V. Langhoff" itemprop="image">
|
||
|
|
||
|
</div>
|
||
|
|
||
|
|
||
|
<div class="author__content">
|
||
|
|
||
|
<h3 class="author__name" itemprop="name">Tobias V. Langhoff</h3>
|
||
|
|
||
|
|
||
|
<div class="author__bio" itemprop="description">
|
||
|
<p>Software developer from Norway</p>
|
||
|
|
||
|
</div>
|
||
|
|
||
|
</div>
|
||
|
|
||
|
<div class="author__urls-wrapper">
|
||
|
<button class="btn btn--inverse">Follow</button>
|
||
|
<ul class="author__urls social-icons">
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<li><a href="https://twitter.com/Spug" rel="nofollow noopener noreferrer"><i class="fab fa-fw fa-twitter" aria-hidden="true"></i><span class="label">@Spug</span></a></li>
|
||
|
|
||
|
|
||
|
|
||
|
<li><a href="https://github.com/tobiasvl" rel="nofollow noopener noreferrer"><i class="fab fa-fw fa-github" aria-hidden="true"></i><span class="label">tobiasvl</span></a></li>
|
||
|
|
||
|
|
||
|
|
||
|
<li><a href="https://tobiasvl.itch.io/" rel="nofollow noopener noreferrer"><i class="fab fa-fw fa-itch-io" aria-hidden="true"></i><span class="label">tobiasvl</span></a></li>
|
||
|
|
||
|
|
||
|
|
||
|
<li><a href="https://tvil.bandcamp.com/" rel="nofollow noopener noreferrer"><i class="fab fa-fw fa-bandcamp" aria-hidden="true"></i><span class="label">tvil</span></a></li>
|
||
|
|
||
|
|
||
|
|
||
|
<li><a href="https://instagram.com/spugster" rel="nofollow noopener noreferrer"><i class="fab fa-fw fa-instagram" aria-hidden="true"></i><span class="label">spugster</span></a></li>
|
||
|
|
||
|
|
||
|
|
||
|
<li><a href="https://www.trueachievements.com/gamer/tobiasvl/gamecollection" rel="nofollow noopener noreferrer"><i class="fab fa-fw fa-xbox" aria-hidden="true"></i><span class="label">tobiasvl</span></a></li>
|
||
|
|
||
|
|
||
|
|
||
|
<li><a href="https://https//www.last.fm/user/Spug" rel="nofollow noopener noreferrer"><i class="fab fa-fw fa-lastfm-square" aria-hidden="true"></i><span class="label">Spug</span></a></li>
|
||
|
|
||
|
|
||
|
|
||
|
<li><a href="https://www.goodreads.com/user/show/11408214-tobias-langhoff" rel="nofollow noopener noreferrer"><i class="fab fa-fw fa-goodreads" aria-hidden="true"></i><span class="label">Goodreads</span></a></li>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<!--
|
||
|
<li>
|
||
|
<a href="http://link-to-whatever-social-network.com/user/" itemprop="sameAs" rel="nofollow noopener noreferrer">
|
||
|
<i class="fas fa-fw" aria-hidden="true"></i> Custom Social Profile Link
|
||
|
</a>
|
||
|
</li>
|
||
|
-->
|
||
|
</ul>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
|
||
|
</div>
|
||
|
|
||
|
|
||
|
|
||
|
<article class="page" itemscope="" itemtype="https://schema.org/CreativeWork">
|
||
|
<meta itemprop="headline" content="Guide to making a CHIP-8 emulator">
|
||
|
<meta itemprop="description" content="A high-level guide to making a CHIP-8 emulator.">
|
||
|
<meta itemprop="datePublished" content="2020-07-20T00:00:00+00:00">
|
||
|
|
||
|
|
||
|
<div class="page__inner-wrap">
|
||
|
|
||
|
<header>
|
||
|
<h1 id="page-title" class="page__title" itemprop="headline">Guide to making a CHIP-8 emulator
|
||
|
</h1>
|
||
|
|
||
|
|
||
|
<p class="page__meta">
|
||
|
|
||
|
|
||
|
<span class="page__meta-date">
|
||
|
<i class="far fa-calendar-alt" aria-hidden="true"></i>
|
||
|
|
||
|
<time datetime="2020-07-20T00:00:00+00:00">July 20, 2020</time>
|
||
|
</span>
|
||
|
|
||
|
|
||
|
<span class="page__meta-sep"></span>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<span class="page__meta-readtime">
|
||
|
<i class="far fa-clock" aria-hidden="true"></i>
|
||
|
|
||
|
30 minute read
|
||
|
|
||
|
</span>
|
||
|
|
||
|
</p>
|
||
|
|
||
|
|
||
|
</header>
|
||
|
|
||
|
|
||
|
<section class="page__content" itemprop="text">
|
||
|
|
||
|
<aside class="sidebar__right ">
|
||
|
<nav class="toc">
|
||
|
<header><h4 class="nav__title"><i class="fas fa-file-alt"></i> On this page</h4></header>
|
||
|
<ul class="toc__menu"><li><a href="#history">History</a></li><li><a href="#prerequisites">Prerequisites</a></li><li><a href="#specifications">Specifications</a></li><li><a href="#memory">Memory</a></li><li><a href="#font">Font</a></li><li><a href="#display">Display</a></li><li><a href="#stack">Stack</a></li><li><a href="#timers">Timers</a></li><li><a href="#keypad">Keypad</a></li><li><a href="#fetchdecodeexecute-loop">Fetch/decode/execute loop</a><ul><li><a href="#timing">Timing</a></li><li><a href="#fetch">Fetch</a></li><li><a href="#decode">Decode</a></li><li class=""><a href="#execute">Execute</a></li></ul></li><li class=""><a href="#instructions">Instructions</a><ul><li class=""><a href="#0nnn-execute-machine-language-routine">0NNN: Execute machine language routine</a></li><li class=""><a href="#00e0-clear-screen">00E0: Clear screen</a></li><li class=""><a href="#1nnn-jump">1NNN: Jump</a></li><li class=""><a href="#00ee-and-2nnn-subroutines">00EE and 2NNN: Subroutines</a></li><li class=""><a href="#3xnn-4xnn-5xy0-and-9xy0-skip">3XNN, 4XNN, 5XY0 and 9XY0: Skip</a></li><li class=""><a href="#6xnn-set">6XNN: Set</a></li><li class=""><a href="#7xnn-add">7XNN: Add</a></li><li class=""><a href="#logical-and-arithmetic-instructions">Logical and arithmetic instructions</a><ul><li class=""><a href="#8xy0-set">8XY0: Set</a></li><li class=""><a href="#8xy1-binary-or">8XY1: Binary OR</a></li><li class=""><a href="#8xy2-binary-and">8XY2: Binary AND</a></li><li><a href="#8xy3-logical-xor">8XY3: Logical XOR</a></li><li class=""><a href="#8xy4-add">8XY4: Add</a></li><li class=""><a href="#8xy5-and-8xy7-subtract">8XY5 and 8XY7: Subtract</a></li><li class=""><a href="#8xy6-and-8xye-shift">8XY6 and 8XYE: Shift</a></li></ul></li><li class=""><a href="#annn-set-index">ANNN: Set index</a></li><li class=""><a href="#bnnn-jump-with-offset">BNNN: Jump with offset</a></li><li class=""><a href="#cxnn-random">CXNN: Random</a></li><li class=""><a href="#dxyn-display">DXYN: Display</a></li><li class=""><a href="#ex9e-and-exa1-skip-if-key">EX9E and EXA1: Skip if key</a></li><li class=""><a href="#fx07-fx15-and-fx18-timers">FX07, FX15 and FX18: Timers</a></li><li class=""><a href="#fx1e-add-to-index">FX1E: Add to index</a></li><li class=""><a href="#fx0a-get-key">FX0A: Get key</a></li><li class=""><a href="#fx29-font-character">FX29: Font character</a></li><li class=""><a href="#fx33-binary-coded-decimal-conversion">FX33: Binary-coded decimal conversion</a></li><li class=""><a href="#fx55-and-fx65-store-and-load-memory">FX55 and FX65: Store and load memory</a></li></ul></li><li class=""><a href="#troubleshooting">Troubleshooting</a></li><li class=""><a href="#what-next">What next</a><ul><li class="active"><a href="#make-your-own-chip-8-game">Make your own CHIP-8 game!</a></li><li><a href="#add-super-chip-support">Add SUPER-CHIP support</a></li><li><a href="#add-debug-capabilities">Add debug capabilities</a></li><li><a href="#add-xo-chip-support">Add XO-CHIP support</a></li><li><a href="#make-a-chip-8-emulator-for-an-obscure-system">Make a CHIP-8 emulator for an obscure system</a></li></ul></li></ul>
|
||
|
|
||
|
</nav>
|
||
|
</aside>
|
||
|
|
||
|
<!-- #blog/published -->
|
||
|
|
||
|
<p>A high-level guide to making a CHIP-8 emulator.</p>
|
||
|
|
||
|
<!--more-->
|
||
|
|
||
|
<p>Do you want to get into emulator development? A common advice is to start out with <a href="https://en.wikipedia.org/wiki/CHIP-8">CHIP-8</a>. But how do you do that? And why are there so many different, conflicting specifications?</p>
|
||
|
|
||
|
<p>This is a guide for you. It will tell you how to make a CHIP-8
|
||
|
emulator, but it won’t give away the code. It will explain what each
|
||
|
part should do, and use some pseudocode at times, but the actual
|
||
|
implementation will be up to you.</p>
|
||
|
|
||
|
<p>Along the way I’ll put tips in green boxes, warnings in orange boxes
|
||
|
(things to look out for), and trivia (mostly historical) in blue boxes.
|
||
|
Like this one:</p>
|
||
|
|
||
|
<p class="notice--info">Everyone calls them “CHIP-8 emulators”, since
|
||
|
they’re a common starting point for learning how to develop emulators,
|
||
|
but they’re not actually emulators. An emulator <em>emulates</em> physical hardware in software, but CHIP-8 isn’t a piece of hardware. To be pedantic, you’re writing a CHIP-8 <em>interpreter</em>.</p>
|
||
|
|
||
|
<p>If you have any suggestions for this guide, or just want to show off
|
||
|
an emulator you’ve made, please leave a comment at the end of the page!</p>
|
||
|
|
||
|
<h2 id="history">History<a class="header-link" href="#history" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h2>
|
||
|
|
||
|
<p>CHIP-8 was created by RCA engineer Joe Weisbecker in 1977 for the
|
||
|
COSMAC VIP microcomputer. It was intended as a simpler way to make small
|
||
|
programs and games for the computer. Instead of using machine language
|
||
|
for the VIP’s CDP1802 processor, you could type in hexadecimal
|
||
|
instructions (with the VIP’s hex keypad) that resembled machine code,
|
||
|
but which were more high-level, and interpreted on the fly by a small
|
||
|
program (the CHIP-8 emulator/interpreter).</p>
|
||
|
|
||
|
<p>CHIP-8 soon spread to other computers, like the Finnish Telmac 1800,
|
||
|
the Australian DREAM 6800, ETI-660 and MicroBee, and the Canadian ACE
|
||
|
VDU.</p>
|
||
|
|
||
|
<p>By 1984 the interest in CHIP-8 petered out. However, in 1990 it had a
|
||
|
renaissance on the HP48 graphing calculators with CHIP-48 and the
|
||
|
now-famous SUPER-CHIP extension with higher resolution.</p>
|
||
|
|
||
|
<p>With so many different implementations over several decades, there
|
||
|
are many inconsistent specifications. I’ll clear those up for you along
|
||
|
the way.</p>
|
||
|
|
||
|
<p class="notice--info">Michael J. Bauer, who made the DREAM 6800
|
||
|
computer and its CHIP-8 interpreter in 1978, invented the following
|
||
|
backronym for CHIP-8: <strong>Compact Hexadecimal Interpretive Programming – 8-bit</strong>.</p>
|
||
|
|
||
|
<h2 id="prerequisites">Prerequisites<a class="header-link" href="#prerequisites" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h2>
|
||
|
|
||
|
<p>This is a CHIP-8 tutorial, not a programming tutorial. You should
|
||
|
already know some programming before making an emulator, in my opinion,
|
||
|
or you’ll have a rough time.</p>
|
||
|
|
||
|
<p>You will also need to have a basic understanding of the binary and
|
||
|
hexadecimal number systems; I will write hexadecimal numbers like this: <code class="language-plaintext highlighter-rouge">B3</code>. CHIP-8 programs are binary files, and your emulator will need to read these files and operate on the bytes.</p>
|
||
|
|
||
|
<p>You will also need a way to draw graphics to the screen, and read
|
||
|
keypresses. Many graphical libraries can do this for you, or you can use
|
||
|
something like <a href="https://www.libsdl.org/">SDL</a> directly.</p>
|
||
|
|
||
|
<h2 id="specifications">Specifications<a class="header-link" href="#specifications" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h2>
|
||
|
|
||
|
<p>CHIP-8 has the following components:</p>
|
||
|
|
||
|
<ul>
|
||
|
<li><em>Memory</em>: CHIP-8 has direct access to up to 4 kilobytes of RAM</li>
|
||
|
<li><em>Display</em>: 64 x 32 pixels (or 128 x 64 for SUPER-CHIP) monochrome, ie. black or white</li>
|
||
|
<li>A <em>program counter</em>, often called just “PC”, which points at the current instruction in memory</li>
|
||
|
<li>One 16-bit <em>index register</em> called “I” which is used to point at locations in memory</li>
|
||
|
<li>A <em>stack</em> for 16-bit addresses, which is used to call subroutines/functions and return from them</li>
|
||
|
<li>An 8-bit <em>delay timer</em> which is decremented at a rate of 60 Hz (60 times per second) until it reaches 0</li>
|
||
|
<li>An 8-bit <em>sound timer</em> which functions like the delay timer, but which also gives off a beeping sound as long as it’s not 0</li>
|
||
|
<li>16 8-bit (one byte) general-purpose <em>variable</em> registers numbered <code class="language-plaintext highlighter-rouge">0</code> through <code class="language-plaintext highlighter-rouge">F</code> hexadecimal, ie. 0 through 15 in decimal, called <code class="language-plaintext highlighter-rouge">V0</code> through <code class="language-plaintext highlighter-rouge">VF</code>
|
||
|
<ul>
|
||
|
<li><code class="language-plaintext highlighter-rouge">VF</code> is also used as a <em>flag register</em>; many instructions will set it to either 1 or 0 based on some rule, for example using it as a carry flag</li>
|
||
|
</ul>
|
||
|
</li>
|
||
|
</ul>
|
||
|
|
||
|
<p>That’s it!</p>
|
||
|
|
||
|
<h2 id="memory">Memory<a class="header-link" href="#memory" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h2>
|
||
|
|
||
|
<p>The memory should be 4 kB (4 kilobytes, ie. 4096 bytes) large.
|
||
|
CHIP-8’s index register and program counter can only address 12 bits
|
||
|
(conveniently), which is 4096 addresses.</p>
|
||
|
|
||
|
<p class="notice--info">The index register, program counter and stack
|
||
|
entries are all actually 16 bits long. In theory, they could increment
|
||
|
beyond 4 kB of memory addresses. In practice, no CHIP-8 games do that.
|
||
|
The early computers running CHIP-8 usually had less than 4 kB of RAM
|
||
|
anyway.</p>
|
||
|
|
||
|
<p>All the memory is RAM and should be considered to be writable. CHIP-8 games can, and do, modify themselves.</p>
|
||
|
|
||
|
<p class="notice--info">CHIP-8 programs you find online as binary files
|
||
|
are often called “ROMs”, like game files for video game emulators, but
|
||
|
unlike games on console cartridges they were not actually ROM (which
|
||
|
means “read-only memory”).</p>
|
||
|
|
||
|
<p>The first CHIP-8 interpreter (on the COSMAC VIP computer) was also located in RAM, from address <code class="language-plaintext highlighter-rouge">000</code> to <code class="language-plaintext highlighter-rouge">1FF</code>. It would expect a CHIP-8 program to be loaded into memory after it, starting at address <code class="language-plaintext highlighter-rouge">200</code>
|
||
|
(512 in decimal). Although modern interpreters are not in the same
|
||
|
memory space, you should do the same to be able to run the old programs;
|
||
|
you can just leave the initial space empty, except for the font.</p>
|
||
|
|
||
|
<h2 id="font">Font<a class="header-link" href="#font" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h2>
|
||
|
|
||
|
<p>The CHIP-8 emulator should have a built-in font, with sprite data representing the hexadecimal numbers from <code class="language-plaintext highlighter-rouge">0</code> through <code class="language-plaintext highlighter-rouge">F</code>.
|
||
|
Each font character should be 4 pixels wide by 5 pixels tall. These
|
||
|
font sprites are drawn just like regular sprites (see below).</p>
|
||
|
|
||
|
<p>You should store the font data in memory, because games will draw
|
||
|
these characters like regular sprites: They set the index register I to
|
||
|
the character’s memory location and then draw it. There’s a special
|
||
|
instruction for setting I to a character’s address, so you can choose
|
||
|
where to put it. Anywhere in the first 512 bytes (<code class="language-plaintext highlighter-rouge">000</code>–<code class="language-plaintext highlighter-rouge">1FF</code>) is fine. For some reason, it’s become popular to put it at <code class="language-plaintext highlighter-rouge">050</code>–<code class="language-plaintext highlighter-rouge">09F</code>, so you can follow that convention if you want.</p>
|
||
|
|
||
|
<p>The font most people use is represented in bytes like this:</p>
|
||
|
|
||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
|
||
|
0x20, 0x60, 0x20, 0x20, 0x70, // 1
|
||
|
0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
|
||
|
0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
|
||
|
0x90, 0x90, 0xF0, 0x10, 0x10, // 4
|
||
|
0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
|
||
|
0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
|
||
|
0xF0, 0x10, 0x20, 0x40, 0x40, // 7
|
||
|
0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
|
||
|
0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
|
||
|
0xF0, 0x90, 0xF0, 0x90, 0x90, // A
|
||
|
0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
|
||
|
0xF0, 0x80, 0x80, 0x80, 0xF0, // C
|
||
|
0xE0, 0x90, 0x90, 0x90, 0xE0, // D
|
||
|
0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
|
||
|
0xF0, 0x80, 0xF0, 0x80, 0x80 // F
|
||
|
</code></pre></div></div>
|
||
|
|
||
|
<!-- TODO FONT IMAGE -->
|
||
|
|
||
|
<p class="notice--info">In theory you could design your own font; it’s unlikely that any games rely on the shapes of the characters. Many of <a href="https://github.com/mattmikolay/chip-8/issues/3">the early computer implementations had their own fonts</a>.</p>
|
||
|
|
||
|
<h2 id="display">Display<a class="header-link" href="#display" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h2>
|
||
|
|
||
|
<p>The display is 64 pixels wide and 32 pixels tall. Each pixel can be <em>on</em> or <em>off</em>. In other words, each pixel is a boolean value, or a bit.</p>
|
||
|
|
||
|
<p class="notice--info">The early computers used regular TVs as screens,
|
||
|
so an “off” pixel was just black, and “on” was white. You can pick
|
||
|
other colors.</p>
|
||
|
|
||
|
<p>Original interpreters updated the display at 60 Hz (ie. they had 60
|
||
|
FPS, to use modern terminology). How you do this is up to you, but
|
||
|
depending on the framework you use, it might be a good idea to only
|
||
|
redraw the screen when your emulator executes an instruction that
|
||
|
modifies the display data (there are two), to run faster.</p>
|
||
|
|
||
|
<p>The details of the drawing instruction <code class="language-plaintext highlighter-rouge">DXYN</code>
|
||
|
are found below, but in short, it is used to draw a “sprite” on the
|
||
|
screen. Each sprite consists of 8-bit bytes, where each bit corresponds
|
||
|
to a horizontal pixel; sprites are between 1 and 15 bytes tall. They’re
|
||
|
drawn to the screen by treating all 0 bits as transparent, and all the 1
|
||
|
bits will “flip” the pixels in the locations of the screen that it’s
|
||
|
drawn to. (You might recognize this as logical XOR.)</p>
|
||
|
|
||
|
<p>This method of drawing will inevitable cause some flickering objects;
|
||
|
when a sprite is moved, it’s first erased from the screen (by simply
|
||
|
drawing it again, flipping all its lit pixels) and then re-drawn in the
|
||
|
new position, so it will disappear for a little while, often causing a
|
||
|
flickering effect. If you want, you can try to think of ways to mitigate
|
||
|
this. For example, pixels that are erased could fade out instead of
|
||
|
disappearing completely, giving an old phosphorous CRT-style effect.</p>
|
||
|
|
||
|
<h2 id="stack">Stack<a class="header-link" href="#stack" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h2>
|
||
|
|
||
|
<p>CHIP-8 has a <a href="https://en.wikipedia.org/wiki/Stack_(abstract_data_type)">stack</a>
|
||
|
(a common “last in, first out” data structure where you can either
|
||
|
“push” data to it or “pop” the last piece of data you pushed). You can
|
||
|
represent it however you’d like; a stack if your programming language
|
||
|
has it, or an array. CHIP-8 uses it to call and return from subroutines
|
||
|
(“functions”) and nothing else, so you will be saving addresses there;
|
||
|
16-bit (or really only 12-bit) numbers.</p>
|
||
|
|
||
|
<p>Early interpreters reserved some memory for the stack, and some
|
||
|
programs would use that knowledge to operate the stack directly and save
|
||
|
stuff there, but you don’t need to do that. You can just use a variable
|
||
|
outside the emulated memory.</p>
|
||
|
|
||
|
<p>These original interpreters had limited space on the stack; usually
|
||
|
at least 16 two-byte entries. You can limit the stack likewise, or just
|
||
|
keep it unlimited. CHIP-8 programs usually don’t nest subroutine calls
|
||
|
too much since the stack was so small originally, so it doesn’t really
|
||
|
matter (unless you encounter a program with a bug that has an infinite
|
||
|
call loop and causes a “stack overflow”).</p>
|
||
|
|
||
|
<h2 id="timers">Timers<a class="header-link" href="#timers" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h2>
|
||
|
|
||
|
<p>There are two separate timer registers: The delay timer and the sound
|
||
|
timer. They both work the same way; they’re one byte in size, and as
|
||
|
long as their value is above 0, they should be decremented by one 60
|
||
|
times per second (ie. at 60 Hz). This is independent of the speed of the
|
||
|
fetch/decode/execute loop below.</p>
|
||
|
|
||
|
<p>The sound timer is special in that it should make the computer “beep” as long as it’s above 0.</p>
|
||
|
|
||
|
<p>Even though it’s called the “delay” timer, your interpreter should
|
||
|
run as normal while it’s being decremented (the same goes for the sound
|
||
|
timer). The CHIP-8 game will check the value of the timer and delay
|
||
|
itself if it wants.</p>
|
||
|
|
||
|
<h2 id="keypad">Keypad<a class="header-link" href="#keypad" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h2>
|
||
|
|
||
|
<p>The earliest computers that CHIP-8 were used with had hexadecimal keypads. These had 16 keys, labelled <code class="language-plaintext highlighter-rouge">0</code> through <code class="language-plaintext highlighter-rouge">F</code>, and were arranged in a 4x4 grid.</p>
|
||
|
|
||
|
<p class="notice--info">On the original COSMAC VIP, a sound (the same
|
||
|
sound as the sound timer uses) would be heard while holding down a key.
|
||
|
This might be a little obnoxious, though…</p>
|
||
|
|
||
|
<p>These keypads all had different layouts, but the COSMAC VIP used the
|
||
|
following layout, which was re-used on the HP48 calculators, so that’s
|
||
|
what everyone implements these days:</p>
|
||
|
|
||
|
<table>
|
||
|
<tbody>
|
||
|
<tr>
|
||
|
<td>1</td>
|
||
|
<td>2</td>
|
||
|
<td>3</td>
|
||
|
<td>C</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td>4</td>
|
||
|
<td>5</td>
|
||
|
<td>6</td>
|
||
|
<td>D</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td>7</td>
|
||
|
<td>8</td>
|
||
|
<td>9</td>
|
||
|
<td>E</td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td>A</td>
|
||
|
<td>0</td>
|
||
|
<td>B</td>
|
||
|
<td>F</td>
|
||
|
</tr>
|
||
|
</tbody>
|
||
|
</table>
|
||
|
|
||
|
<figure class="">
|
||
|
<img src="Guide%20to%20making%20a%20CHIP-8%20emulator%20-%20Tobias%20V_files/cosmac-vip-keypad.png" alt=""><figcaption>
|
||
|
The COSMAC VIP keypad
|
||
|
|
||
|
</figcaption></figure>
|
||
|
|
||
|
<p class="notice--info">If you want to support a wide range of CHIP-8
|
||
|
games for different computers, you could add options for other
|
||
|
arrangements of the keys. The other most common layout (used by many
|
||
|
DREAM 6800 and ETI-660 computers) started with <code class="language-plaintext highlighter-rouge">0</code> in the upper left corner and ran down to <code class="language-plaintext highlighter-rouge">F</code> in the bottom right corner.</p>
|
||
|
|
||
|
<p>For CHIP-8 emulators that run on modern PCs, it’s customary to use the left side of the QWERTY keyboard for this:</p>
|
||
|
|
||
|
<table>
|
||
|
<tbody>
|
||
|
<tr>
|
||
|
<td><kbd>1</kbd></td>
|
||
|
<td><kbd>2</kbd></td>
|
||
|
<td><kbd>3</kbd></td>
|
||
|
<td><kbd>4</kbd></td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td><kbd>Q</kbd></td>
|
||
|
<td><kbd>W</kbd></td>
|
||
|
<td><kbd>E</kbd></td>
|
||
|
<td><kbd>R</kbd></td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td><kbd>A</kbd></td>
|
||
|
<td><kbd>S</kbd></td>
|
||
|
<td><kbd>D</kbd></td>
|
||
|
<td><kbd>F</kbd></td>
|
||
|
</tr>
|
||
|
<tr>
|
||
|
<td><kbd>Z</kbd></td>
|
||
|
<td><kbd>X</kbd></td>
|
||
|
<td><kbd>C</kbd></td>
|
||
|
<td><kbd>V</kbd></td>
|
||
|
</tr>
|
||
|
</tbody>
|
||
|
</table>
|
||
|
|
||
|
<p class="notice--success">You will probably want to use keyboard <em>scancodes</em> rather than key string constants, so people who use different keyboard layouts (like AZERTY) can use your emulator.</p>
|
||
|
|
||
|
<h2 id="fetchdecodeexecute-loop">Fetch/decode/execute loop<a class="header-link" href="#fetchdecodeexecute-loop" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h2>
|
||
|
|
||
|
<p>An emulator’s main task is simple. It runs in an infinite loop, and does these three tasks in succession:</p>
|
||
|
|
||
|
<ul>
|
||
|
<li><strong>Fetch</strong> the instruction from memory at the current PC (program counter)</li>
|
||
|
<li><strong>Decode</strong> the instruction to find out what the emulator should do</li>
|
||
|
<li><strong>Execute</strong> the instruction and do what it tells you</li>
|
||
|
</ul>
|
||
|
|
||
|
<p>I’ll go through each of these steps below, but first: What speed
|
||
|
should this loop run at? If you just run it as-is, your powerful
|
||
|
computer will probably run the games way too fast to be playable.</p>
|
||
|
|
||
|
<h3 id="timing">Timing<a class="header-link" href="#timing" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>The original CHIP-8 computers had processors that ran at something
|
||
|
like 1 MHz, and the 90s HP48 calculators ran at around 4 MHz. That
|
||
|
doesn’t tell us much, since the CHIP-8 instructions took a different
|
||
|
number of cycles to run in their machine code implementations – and on
|
||
|
different computers back then – but it does mean that different games
|
||
|
might expect to run at different speeds, so you will probably want to
|
||
|
make it configurable.</p>
|
||
|
|
||
|
<p class="notice--info">For the original timings for CHIP-8 instructions in the COSMAC VIP interpreter, see this page: <a href="https://jackson-s.me/2019/07/13/Chip-8-Instruction-Scheduling-and-Frequency.html">Chip 8 Instruction Scheduling and Frequency</a>.</p>
|
||
|
|
||
|
<p>In practice, a standard speed of around 700 CHIP-8 instructions per
|
||
|
second fits well enough for most CHIP-8 programs you’ll find, which are
|
||
|
mostly from the 90s. Play a few different ones and get a feel for what
|
||
|
speed seems right.</p>
|
||
|
|
||
|
<h3 id="fetch">Fetch<a class="header-link" href="#fetch" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>Read the instruction that PC is currently pointing at from memory. An
|
||
|
instruction is two bytes, so you will need to read two successive bytes
|
||
|
from memory and combine them into one 16-bit instruction.</p>
|
||
|
|
||
|
<p>You should then immediately increment the PC by 2, to be ready to
|
||
|
fetch the next opcode. Some people do this during the “execute” stage,
|
||
|
since some instructions will increment it by 2 more to skip an
|
||
|
instruction, but in my opinion that’s very error-prone. Code duplication
|
||
|
is a bad thing. If you forget to increment it in one of the
|
||
|
instructions, you’ll have problems. Do it here!</p>
|
||
|
|
||
|
<h3 id="decode">Decode<a class="header-link" href="#decode" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>Other systems than CHIP-8 will have a more advanced “decode” stage
|
||
|
(the opcode could have different addressing modes, operands, etc.). For
|
||
|
CHIP-8, it’s pretty simple.</p>
|
||
|
|
||
|
<p>CHIP-8 instructions are divided into broad categories by the first
|
||
|
“nibble”, or “half-byte”, which is the first hexadecimal number. So, you
|
||
|
basically just want to do a huge <code class="language-plaintext highlighter-rouge">if</code>/<code class="language-plaintext highlighter-rouge">elseif</code> statement here, doing different things depending on what the first number is.</p>
|
||
|
|
||
|
<p>If your language supports <code class="language-plaintext highlighter-rouge">switch</code>
|
||
|
statements, that’s by far the easiest way to go. Mask off (with a
|
||
|
“binary AND”) the first number in the instruction, and have one <code class="language-plaintext highlighter-rouge">case</code> per number. Some of these cases will need separate <code class="language-plaintext highlighter-rouge">switch</code> statements inside them to further decode the instruction.</p>
|
||
|
|
||
|
<p class="notice--warning">In C or C++, remember to <code class="language-plaintext highlighter-rouge">break;</code> inside each case, or you’ll “fall through” to the next.</p>
|
||
|
|
||
|
<p>Although every instruction will have a first nibble that tells you
|
||
|
what kind of instruction it is, the rest of the nibbles will have
|
||
|
different meanings. To differentiate these meanings, we usually call
|
||
|
them different things, but all of them can be any hexadecimal number
|
||
|
from 0 to F:</p>
|
||
|
|
||
|
<ul>
|
||
|
<li><code class="language-plaintext highlighter-rouge">X</code>: The second nibble. Used to look up one of the 16 registers (<code class="language-plaintext highlighter-rouge">VX</code>) from <code class="language-plaintext highlighter-rouge">V0</code> through <code class="language-plaintext highlighter-rouge">VF</code>.</li>
|
||
|
<li><code class="language-plaintext highlighter-rouge">Y</code>: The third nibble. Also used to look up one of the 16 registers (<code class="language-plaintext highlighter-rouge">VY</code>) from <code class="language-plaintext highlighter-rouge">V0</code> through <code class="language-plaintext highlighter-rouge">VF</code>.</li>
|
||
|
<li><code class="language-plaintext highlighter-rouge">N</code>: The fourth nibble. A 4-bit number.</li>
|
||
|
<li><code class="language-plaintext highlighter-rouge">NN</code>: The second byte (third and fourth nibbles). An 8-bit immediate number.</li>
|
||
|
<li><code class="language-plaintext highlighter-rouge">NNN</code>: The second, third and fourth nibbles. A 12-bit immediate memory address.</li>
|
||
|
</ul>
|
||
|
|
||
|
<p>To avoid code duplication again, I suggest you extract these values
|
||
|
from the opcode before decoding, instead of doing it inside each
|
||
|
instruction. If you do it wrong just one place, you’ll have a hard time
|
||
|
tracking that down.</p>
|
||
|
|
||
|
<p class="notice--info">If you use C or another language with <code class="language-plaintext highlighter-rouge">#define</code> or other macro directives, using that is probably a good idea!</p>
|
||
|
|
||
|
<p>Note that <code class="language-plaintext highlighter-rouge">X</code> and <code class="language-plaintext highlighter-rouge">Y</code>
|
||
|
are always used to look up the values in registers. One mistake I see a
|
||
|
lot of make early on (and I’ve done it myself) is that they’ll use the
|
||
|
acual value <code class="language-plaintext highlighter-rouge">X</code> in the instruction. You never want that! That’s only for the <code class="language-plaintext highlighter-rouge">N</code> operands. <code class="language-plaintext highlighter-rouge">X</code> and <code class="language-plaintext highlighter-rouge">Y</code> should always look up a value in the corresponding register.</p>
|
||
|
|
||
|
<h3 id="execute" class="">Execute<a class="header-link" href="#execute" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>For CHIP-8, if you went with the <code class="language-plaintext highlighter-rouge">switch</code> approach (or similar), this won’t really be a separate stage. Just directly do what the instruction should do inside each <code class="language-plaintext highlighter-rouge">case</code>.</p>
|
||
|
|
||
|
<p>In emulators for other systems, you might have a whole bunch of
|
||
|
instructions of the same type – say, to add two numbers together – where
|
||
|
the operands can be registers,
|
||
|
memory locations, immediate values, etc. (these are called addressing
|
||
|
modes). But for CHIP-8, that doesn’t matter.</p>
|
||
|
|
||
|
<h2 id="instructions" class="">Instructions<a class="header-link" href="#instructions" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h2>
|
||
|
|
||
|
<p>It’s time to actually decode the instructions! Just go one by one.</p>
|
||
|
|
||
|
<p>A small tip here. I suggest you start out with the following instructions:</p>
|
||
|
|
||
|
<ul>
|
||
|
<li><code class="language-plaintext highlighter-rouge">00E0</code> (clear screen)</li>
|
||
|
<li><code class="language-plaintext highlighter-rouge">1NNN</code> (jump)</li>
|
||
|
<li><code class="language-plaintext highlighter-rouge">6XNN</code> (set register <code class="language-plaintext highlighter-rouge">VX</code>)</li>
|
||
|
<li><code class="language-plaintext highlighter-rouge">7XNN</code> (add value to register <code class="language-plaintext highlighter-rouge">VX</code>)</li>
|
||
|
<li><code class="language-plaintext highlighter-rouge">ANNN</code> (set index register I)</li>
|
||
|
<li><code class="language-plaintext highlighter-rouge">DXYN</code> (display/draw)</li>
|
||
|
</ul>
|
||
|
|
||
|
<p>The reason for this is that while you implement these instructions, you can test them very easily with the <strong>IBM logo</strong>
|
||
|
program, which you can easily find online (search “chip-8 ibm logo”).
|
||
|
All this program does is display the IBM logo, and it only uses the
|
||
|
above instructions. This will let you quickly implement the most
|
||
|
important instruction, the “display” instruction <code class="language-plaintext highlighter-rouge">DXYN</code>, which you will need to run more advanced test ROMs since these all display the results on the screen.</p>
|
||
|
|
||
|
<p>If successful, the program should draw the following and then enter an infinite loop:</p>
|
||
|
|
||
|
<figure class="">
|
||
|
<img src="Guide%20to%20making%20a%20CHIP-8%20emulator%20-%20Tobias%20V_files/chip-8_ibm_logo.png" alt=""><figcaption>
|
||
|
The grid has been added as a visual aid while debugging
|
||
|
|
||
|
</figcaption></figure>
|
||
|
|
||
|
<p>When you’ve managed to get this on your display, you can use test
|
||
|
programs to check your implementation of the rest of the instructions as
|
||
|
you go along. There are two main tests:</p>
|
||
|
|
||
|
<ul>
|
||
|
<li>The BonCoder/BestCoder test, <code class="language-plaintext highlighter-rouge">BC_test</code> (can be found online)</li>
|
||
|
<li><a href="https://github.com/corax89/chip8-test-rom">corax89’s chip8-test-rom</a></li>
|
||
|
</ul>
|
||
|
|
||
|
<p>Note that both these test programs rely on the “modern” behavior in
|
||
|
the few ambiguous instructions listed below (I put red warning labels
|
||
|
above their descriptions).</p>
|
||
|
|
||
|
<h3 id="0nnn-execute-machine-language-routine" class=""><code class="language-plaintext highlighter-rouge">0NNN</code>: Execute machine language routine<a class="header-link" href="#0nnn-execute-machine-language-routine" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>We’ll start out with an instruction that you actually don’t want to
|
||
|
implement! In the original CHIP-8 interpreters, this would pause
|
||
|
execution of the CHIP-8 program and call a subroutine written in machine
|
||
|
language at address <code class="language-plaintext highlighter-rouge">NNN</code> instead.</p>
|
||
|
|
||
|
<p>This routine would be written in the machine language of the
|
||
|
computer’s CPU; on the original COSMAC VIP and the ETI-660, this was
|
||
|
1802 machine code, and on the DREAM 6800, M6800 code. Unless you’re
|
||
|
making an emulator for either of those computers, skip this one.</p>
|
||
|
|
||
|
<h3 id="00e0-clear-screen" class=""><code class="language-plaintext highlighter-rouge">00E0</code>: Clear screen<a class="header-link" href="#00e0-clear-screen" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>This is pretty simple: It should clear the display, turning all pixels off to 0.</p>
|
||
|
|
||
|
<h3 id="1nnn-jump" class=""><code class="language-plaintext highlighter-rouge">1NNN</code>: Jump<a class="header-link" href="#1nnn-jump" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>This instruction should simply set PC to <code class="language-plaintext highlighter-rouge">NNN</code>, causing the program to jump to that memory location. Do not increment the PC afterwards, it jumps directly there.</p>
|
||
|
|
||
|
<h3 id="00ee-and-2nnn-subroutines" class=""><code class="language-plaintext highlighter-rouge">00EE</code> and <code class="language-plaintext highlighter-rouge">2NNN</code>: Subroutines<a class="header-link" href="#00ee-and-2nnn-subroutines" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p><code class="language-plaintext highlighter-rouge">2NNN</code> calls the subroutine at memory location <code class="language-plaintext highlighter-rouge">NNN</code>. In other words, just like <code class="language-plaintext highlighter-rouge">1NNN</code>, you should set PC to <code class="language-plaintext highlighter-rouge">NNN</code>.
|
||
|
However, the difference between a jump and a call is that this
|
||
|
instruction should first push the current PC to the stack, so the
|
||
|
subroutine can return later.</p>
|
||
|
|
||
|
<p>Returning from a subroutine is done with <code class="language-plaintext highlighter-rouge">00EE</code>, and it does this by removing (“popping”) the last address from the stack and setting the PC to it.</p>
|
||
|
|
||
|
<h3 id="3xnn-4xnn-5xy0-and-9xy0-skip" class=""><code class="language-plaintext highlighter-rouge">3XNN</code>, <code class="language-plaintext highlighter-rouge">4XNN</code>, <code class="language-plaintext highlighter-rouge">5XY0</code> and <code class="language-plaintext highlighter-rouge">9XY0</code>: Skip<a class="header-link" href="#3xnn-4xnn-5xy0-and-9xy0-skip" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>These instructions do the same thing: They either do nothing, or they
|
||
|
skip one two-byte instruction (increment PC by 2). If you didn’t
|
||
|
increment PC in the “fetch” stage above, they will obviously increment
|
||
|
PC by either 4 or 2.</p>
|
||
|
|
||
|
<p><code class="language-plaintext highlighter-rouge">3XNN</code> will skip one instruction if the value in <code class="language-plaintext highlighter-rouge">VX</code> is equal to <code class="language-plaintext highlighter-rouge">NN</code>, and <code class="language-plaintext highlighter-rouge">4XNN</code> will skip if they are <em>not</em> equal.</p>
|
||
|
|
||
|
<p><code class="language-plaintext highlighter-rouge">5XY0</code> skips if the values in <code class="language-plaintext highlighter-rouge">VX</code> and <code class="language-plaintext highlighter-rouge">VY</code> are equal, while <code class="language-plaintext highlighter-rouge">9XY0</code> skips if they are not equal.</p>
|
||
|
|
||
|
<p>Since these conditional branch instructions can only skip one instructions, they’re usually followed by a jump/call (<code class="language-plaintext highlighter-rouge">1NNN</code>/<code class="language-plaintext highlighter-rouge">2NNN</code>) instruction.</p>
|
||
|
|
||
|
<h3 id="6xnn-set" class=""><code class="language-plaintext highlighter-rouge">6XNN</code>: Set<a class="header-link" href="#6xnn-set" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>Simply set the register <code class="language-plaintext highlighter-rouge">VX</code> to the value <code class="language-plaintext highlighter-rouge">NN</code>.</p>
|
||
|
|
||
|
<h3 id="7xnn-add" class=""><code class="language-plaintext highlighter-rouge">7XNN</code>: Add<a class="header-link" href="#7xnn-add" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>Add the value <code class="language-plaintext highlighter-rouge">NN</code> to <code class="language-plaintext highlighter-rouge">VX</code>.</p>
|
||
|
|
||
|
<p>Note that on most other systems, and even in some of the other CHIP-8
|
||
|
instructions, this would set the carry flag if the result overflowed 8
|
||
|
bits. In other words, if the result of the addition is over 255.</p>
|
||
|
|
||
|
<p>For this instruction, this is not the case. If <code class="language-plaintext highlighter-rouge">V0</code> contains <code class="language-plaintext highlighter-rouge">FF</code> and you execute <code class="language-plaintext highlighter-rouge">6001</code>, the CHIP-8’s flag register <code class="language-plaintext highlighter-rouge">VF</code> is not affected.</p>
|
||
|
|
||
|
<h3 id="logical-and-arithmetic-instructions" class="">Logical and arithmetic instructions<a class="header-link" href="#logical-and-arithmetic-instructions" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>We come to the first group of instructions that need further decoding
|
||
|
beyond just the first nibble! All these instructions are logical or
|
||
|
arithmetic operations, but which one is decided by the last nibble of
|
||
|
the opcode. Do another nested <code class="language-plaintext highlighter-rouge">switch</code> statement (or equivalent) here.</p>
|
||
|
|
||
|
<p class="notice--info">On the COSMAC VIP, all of these instructions changed the value of <code class="language-plaintext highlighter-rouge">VF</code>. Some of them are mentioned below. For the ones that don’t mention affecting <code class="language-plaintext highlighter-rouge">VF</code>, the resulting value in <code class="language-plaintext highlighter-rouge">VF</code>
|
||
|
is undefined. This is because the CHIP-8 interpreter dispatched these
|
||
|
instructions to the 1802 CPU’s ALU circuit, and while doing so it would
|
||
|
change the CPU’s flag register, which always gets copied to <code class="language-plaintext highlighter-rouge">VF</code>.</p>
|
||
|
|
||
|
<h4 id="8xy0-set" class=""><code class="language-plaintext highlighter-rouge">8XY0</code>: Set<a class="header-link" href="#8xy0-set" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h4>
|
||
|
|
||
|
<p><code class="language-plaintext highlighter-rouge">VX</code> is set to the value of <code class="language-plaintext highlighter-rouge">VY</code>.</p>
|
||
|
|
||
|
<h4 id="8xy1-binary-or" class=""><code class="language-plaintext highlighter-rouge">8XY1</code>: Binary OR<a class="header-link" href="#8xy1-binary-or" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h4>
|
||
|
|
||
|
<p><code class="language-plaintext highlighter-rouge">VX</code> is set to the <a href="https://en.wikipedia.org/wiki/Bitwise_operation#OR">bitwise/binary logical disjunction (OR)</a> of <code class="language-plaintext highlighter-rouge">VX</code> and <code class="language-plaintext highlighter-rouge">VY</code>. <code class="language-plaintext highlighter-rouge">VY</code> is not affected.</p>
|
||
|
|
||
|
<h4 id="8xy2-binary-and" class=""><code class="language-plaintext highlighter-rouge">8XY2</code>: Binary AND<a class="header-link" href="#8xy2-binary-and" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h4>
|
||
|
|
||
|
<p><code class="language-plaintext highlighter-rouge">VX</code> is set to the <a href="https://en.wikipedia.org/wiki/Bitwise_operation#AND">bitwise/binary logical conjunction (AND)</a> of <code class="language-plaintext highlighter-rouge">VX</code> and <code class="language-plaintext highlighter-rouge">VY</code>. <code class="language-plaintext highlighter-rouge">VY</code> is not affected.</p>
|
||
|
|
||
|
<h4 id="8xy3-logical-xor"><code class="language-plaintext highlighter-rouge">8XY3</code>: Logical XOR<a class="header-link" href="#8xy3-logical-xor" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h4>
|
||
|
|
||
|
<p><code class="language-plaintext highlighter-rouge">VX</code> is set to the <a href="https://en.wikipedia.org/wiki/Bitwise_operation#XOR">bitwise/binary exclusive OR (XOR)</a> of <code class="language-plaintext highlighter-rouge">VX</code> and <code class="language-plaintext highlighter-rouge">VY</code>. <code class="language-plaintext highlighter-rouge">VY</code> is not affected.</p>
|
||
|
|
||
|
<h4 id="8xy4-add" class=""><code class="language-plaintext highlighter-rouge">8XY4</code>: Add<a class="header-link" href="#8xy4-add" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h4>
|
||
|
|
||
|
<p><code class="language-plaintext highlighter-rouge">VX</code> is set to the value of <code class="language-plaintext highlighter-rouge">VX</code> plus the value of <code class="language-plaintext highlighter-rouge">VY</code>. <code class="language-plaintext highlighter-rouge">VY</code> is not affected.</p>
|
||
|
|
||
|
<p>Unlike <code class="language-plaintext highlighter-rouge">7XNN</code>, this addition will affect the carry flag. If the result is larger than 255 (and thus overflows the 8-bit register <code class="language-plaintext highlighter-rouge">VX</code>), the flag register <code class="language-plaintext highlighter-rouge">VF</code> is set to 1. If it doesn’t overflow, <code class="language-plaintext highlighter-rouge">VF</code> is set to 0.</p>
|
||
|
|
||
|
<h4 id="8xy5-and-8xy7-subtract" class=""><code class="language-plaintext highlighter-rouge">8XY5</code> and <code class="language-plaintext highlighter-rouge">8XY7</code>: Subtract<a class="header-link" href="#8xy5-and-8xy7-subtract" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h4>
|
||
|
|
||
|
<p>These both subtract the value in one register from the other, and put the result in <code class="language-plaintext highlighter-rouge">VX</code>. In both cases, <code class="language-plaintext highlighter-rouge">VY</code> is not affected.</p>
|
||
|
|
||
|
<p><code class="language-plaintext highlighter-rouge">8XY5</code> sets <code class="language-plaintext highlighter-rouge">VX</code> to the result of <code class="language-plaintext highlighter-rouge">VX</code> - <code class="language-plaintext highlighter-rouge">VY</code>.</p>
|
||
|
|
||
|
<p><code class="language-plaintext highlighter-rouge">8XY7</code> sets <code class="language-plaintext highlighter-rouge">VX</code> to the result of <code class="language-plaintext highlighter-rouge">VY</code> - <code class="language-plaintext highlighter-rouge">VX</code>.</p>
|
||
|
|
||
|
<p>This subtraction will also affect the carry flag, but note that it’s
|
||
|
opposite from what you might think. If the minuend (the first operand)
|
||
|
is larger than the subtrahend (second operand), <code class="language-plaintext highlighter-rouge">VF</code> will be set to 1. If the subtrahend is larger, and we “underflow” the result, <code class="language-plaintext highlighter-rouge">VF</code> is set to 0. Another way of thinking of it is that <code class="language-plaintext highlighter-rouge">VF</code> is set to 1 before the subtraction, and then the subtraction either borrows from <code class="language-plaintext highlighter-rouge">VF</code> (setting it to 0) or not.</p>
|
||
|
|
||
|
<h4 id="8xy6-and-8xye-shift" class=""><code class="language-plaintext highlighter-rouge">8XY6</code> and <code class="language-plaintext highlighter-rouge">8XYE</code>: Shift<a class="header-link" href="#8xy6-and-8xye-shift" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h4>
|
||
|
|
||
|
<p class="notice--warning">Ambiguous instruction!</p>
|
||
|
|
||
|
<p>In the CHIP-8 interpreter for the original COSMAC VIP, this instruction did the following: It put the value of <code class="language-plaintext highlighter-rouge">VY</code> into <code class="language-plaintext highlighter-rouge">VX</code>, and then shifted the value in <code class="language-plaintext highlighter-rouge">VX</code> 1 bit to the right (<code class="language-plaintext highlighter-rouge">8XY6</code>) or left (<code class="language-plaintext highlighter-rouge">8XYE</code>). <code class="language-plaintext highlighter-rouge">VY</code> was not affected, but the flag register <code class="language-plaintext highlighter-rouge">VF</code> would be set to the bit that was shifted out.</p>
|
||
|
|
||
|
<p>However, starting with CHIP-48 and SUPER-CHIP in the early 1990s, these instructions were changed so that they shifted <code class="language-plaintext highlighter-rouge">VX</code> in place, and ignored the <code class="language-plaintext highlighter-rouge">Y</code> completely.</p>
|
||
|
|
||
|
<p>This is one of the main differences between implementations that cause problems for programs.</p>
|
||
|
|
||
|
<p>Step by step:</p>
|
||
|
|
||
|
<ol>
|
||
|
<li>(Optional, or configurable) Set <code class="language-plaintext highlighter-rouge">VX</code> to the value of <code class="language-plaintext highlighter-rouge">VY</code></li>
|
||
|
<li>Shift the value of <code class="language-plaintext highlighter-rouge">VX</code> one bit to the right (<code class="language-plaintext highlighter-rouge">8XY6</code>) or left (<code class="language-plaintext highlighter-rouge">8XYE</code>)</li>
|
||
|
<li>Set <code class="language-plaintext highlighter-rouge">VF</code> to 1 if the bit that was shifted out was 1, or 0 if it was 0</li>
|
||
|
</ol>
|
||
|
|
||
|
<h3 id="annn-set-index" class=""><code class="language-plaintext highlighter-rouge">ANNN</code>: Set index<a class="header-link" href="#annn-set-index" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>This sets the index register I to the value <code class="language-plaintext highlighter-rouge">NNN</code>.</p>
|
||
|
|
||
|
<h3 id="bnnn-jump-with-offset" class=""><code class="language-plaintext highlighter-rouge">BNNN</code>: Jump with offset<a class="header-link" href="#bnnn-jump-with-offset" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p class="notice--warning">Ambiguous instruction!</p>
|
||
|
|
||
|
<p>In the original COSMAC VIP interpreter, this instruction jumped to the address <code class="language-plaintext highlighter-rouge">NNN</code> plus the value in the register <code class="language-plaintext highlighter-rouge">V0</code>. This was mainly used for “jump tables”, to quickly be able to jump to different subroutines based on some input.</p>
|
||
|
|
||
|
<p>Starting with CHIP-48 and SUPER-CHIP, it was (probably unintentionally) changed to work as <code class="language-plaintext highlighter-rouge">BXNN</code>: It will jump to the address <code class="language-plaintext highlighter-rouge">XNN</code>, plus the value in the register <code class="language-plaintext highlighter-rouge">VX</code>. So the instruction <code class="language-plaintext highlighter-rouge">B220</code> will jump to address <code class="language-plaintext highlighter-rouge">220</code> plus the value in the register <code class="language-plaintext highlighter-rouge">V2</code>.</p>
|
||
|
|
||
|
<p>The <code class="language-plaintext highlighter-rouge">BNNN</code>
|
||
|
instruction was not widely used, so you might be able to just implement
|
||
|
the first behavior (if you pick one, that’s definitely the one to go
|
||
|
with). If you want to support a wide range of CHIP-8 programs, make this
|
||
|
“quirk” configurable.</p>
|
||
|
|
||
|
<h3 id="cxnn-random" class=""><code class="language-plaintext highlighter-rouge">CXNN</code>: Random<a class="header-link" href="#cxnn-random" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>This instruction generates a random number, binary ANDs it with the value <code class="language-plaintext highlighter-rouge">NN</code>, and puts the result in <code class="language-plaintext highlighter-rouge">VX</code>.</p>
|
||
|
|
||
|
<p>Most likely your programming language has a function for generating random numbers. It will work fine for this use.</p>
|
||
|
|
||
|
<p class="notice--warning">Note that you should not simply generate a random number between 0 and <code class="language-plaintext highlighter-rouge">NN</code>! You need to do a binary AND.</p>
|
||
|
|
||
|
<h3 id="dxyn-display" class=""><code class="language-plaintext highlighter-rouge">DXYN</code>: Display<a class="header-link" href="#dxyn-display" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>This is the most involved instruction. It will draw an <code class="language-plaintext highlighter-rouge">N</code> pixels tall sprite from the memory location that the <code class="language-plaintext highlighter-rouge">I</code> index register is holding to the screen, at the horizontal X coordinate in <code class="language-plaintext highlighter-rouge">VX</code> and the Y coordinate in <code class="language-plaintext highlighter-rouge">VY</code>.
|
||
|
All the pixels that are “on” in the sprite will flip the pixels on the
|
||
|
screen that it is drawn to (from left to right, from most to least
|
||
|
significant bit). If any pixels on the screen were turned “off” by this,
|
||
|
the <code class="language-plaintext highlighter-rouge">VF</code> flag register is set to 1. Otherwise, it’s set to 0.</p>
|
||
|
|
||
|
<p>Sounds hard? Well, it is, a little.</p>
|
||
|
|
||
|
<p>The first thing to do is to get the X and Y coordinates from <code class="language-plaintext highlighter-rouge">VX</code> and <code class="language-plaintext highlighter-rouge">VY</code>.</p>
|
||
|
|
||
|
<p>A common mistake here is to use <code class="language-plaintext highlighter-rouge">X</code> and <code class="language-plaintext highlighter-rouge">Y</code> directly; don’t do that, fetch them from the registers.</p>
|
||
|
|
||
|
<p>One area where people get confused is whether sprites should wrap if
|
||
|
they go over the edge of the screen. The answer is yes and no.</p>
|
||
|
|
||
|
<p>The starting position of the sprite will wrap. In other words, an X
|
||
|
coordinate of 5 is the same as an X of 68 (since the screen is 64 pixels
|
||
|
wide). Another way of saying it is that the coordinates are <em>modulo</em> (or binary AND) the size of the display (when counting from 0).</p>
|
||
|
|
||
|
<p>However, the actual drawing of the sprite should not wrap. If a
|
||
|
sprite is drawn near the edge of the screen, it should be clipped, and
|
||
|
not wrap. The sprite should be partly drawn near the edge, and the other
|
||
|
part should not reappear on the opposite side of the screen.</p>
|
||
|
|
||
|
<p>Skip this if you want to try to implement it yourself first, but
|
||
|
here’s a step by step summary of what this instruction should do:</p>
|
||
|
|
||
|
<ul>
|
||
|
<li>Set the X coordinate to the value in <code class="language-plaintext highlighter-rouge">VX</code> <em>modulo</em> 64 (or, equivalently, <code class="language-plaintext highlighter-rouge">VX & 63</code>, where & is the binary AND operation)</li>
|
||
|
<li>Set the Y coordinate to the value in <code class="language-plaintext highlighter-rouge">VY</code> <em>modulo</em> 32 (or <code class="language-plaintext highlighter-rouge">VY & 31</code>)</li>
|
||
|
<li>Set <code class="language-plaintext highlighter-rouge">VF</code> to 0</li>
|
||
|
<li>For <code class="language-plaintext highlighter-rouge">N</code> rows:
|
||
|
<ul>
|
||
|
<li>Get the Nth byte of sprite data, counting from the memory address in the <code class="language-plaintext highlighter-rouge">I</code> register (<code class="language-plaintext highlighter-rouge">I</code> is not incremented)</li>
|
||
|
<li>For each of the 8 pixels/bits in this sprite row (from left to right, ie. from most to least significant bit):
|
||
|
<ul>
|
||
|
<li>If the current pixel in the sprite row is on and the pixel
|
||
|
at coordinates X,Y on the screen is also on, turn off the pixel and set
|
||
|
<code class="language-plaintext highlighter-rouge">VF</code> to 1</li>
|
||
|
<li>Or if the current pixel in the sprite row is on and the screen pixel is not, draw the pixel at the X and Y coordinates</li>
|
||
|
<li>If you reach the right edge of the screen, stop drawing this row</li>
|
||
|
<li>Increment X (<code class="language-plaintext highlighter-rouge">VX</code> is not incremented)</li>
|
||
|
</ul>
|
||
|
</li>
|
||
|
<li>Increment Y (<code class="language-plaintext highlighter-rouge">VY</code> is not incremented)</li>
|
||
|
<li>Stop if you reach the bottom edge of the screen</li>
|
||
|
</ul>
|
||
|
</li>
|
||
|
</ul>
|
||
|
|
||
|
<p>Phew! Don’t worry, this is the worst one.</p>
|
||
|
|
||
|
<h3 id="ex9e-and-exa1-skip-if-key" class=""><code class="language-plaintext highlighter-rouge">EX9E</code> and <code class="language-plaintext highlighter-rouge">EXA1</code>: Skip if key<a class="header-link" href="#ex9e-and-exa1-skip-if-key" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>Like the earlier skip instructions, these two also skip the following
|
||
|
instruction based on a condition. These skip based on whether the
|
||
|
player is currently pressing a key or not.</p>
|
||
|
|
||
|
<p>These instructions (unlike the later <code class="language-plaintext highlighter-rouge">FX0A</code>) don’t wait for input, they just check if the key is currently being held down.</p>
|
||
|
|
||
|
<p><code class="language-plaintext highlighter-rouge">EX9E</code> will skip one instruction (increment PC by 2) if the key corresponding to the value in <code class="language-plaintext highlighter-rouge">VX</code> is pressed.</p>
|
||
|
|
||
|
<p><code class="language-plaintext highlighter-rouge">EXA1</code> skips if the key corresponding to the value in <code class="language-plaintext highlighter-rouge">VX</code> is <em>not</em> pressed.</p>
|
||
|
|
||
|
<p>Since the keypad is hexadecimal, the valid values here are keys <code class="language-plaintext highlighter-rouge">0</code>–<code class="language-plaintext highlighter-rouge">F</code>.</p>
|
||
|
|
||
|
<h3 id="fx07-fx15-and-fx18-timers" class=""><code class="language-plaintext highlighter-rouge">FX07</code>, <code class="language-plaintext highlighter-rouge">FX15</code> and <code class="language-plaintext highlighter-rouge">FX18</code>: Timers<a class="header-link" href="#fx07-fx15-and-fx18-timers" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>These all manipulate the timers.</p>
|
||
|
|
||
|
<ul>
|
||
|
<li><code class="language-plaintext highlighter-rouge">FX07</code> sets <code class="language-plaintext highlighter-rouge">VX</code> to the current value of the delay timer</li>
|
||
|
<li><code class="language-plaintext highlighter-rouge">FX15</code> sets the delay timer to the value in <code class="language-plaintext highlighter-rouge">VX</code></li>
|
||
|
<li><code class="language-plaintext highlighter-rouge">FX18</code> sets the sound timer to the value in <code class="language-plaintext highlighter-rouge">VX</code></li>
|
||
|
</ul>
|
||
|
|
||
|
<p>Note that there’s no instruction to read the sound timer; the sound
|
||
|
timer will simply make a beeping sound as long as it’s above 0.</p>
|
||
|
|
||
|
<h3 id="fx1e-add-to-index" class=""><code class="language-plaintext highlighter-rouge">FX1E</code>: Add to index<a class="header-link" href="#fx1e-add-to-index" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>The index register I will get the value in <code class="language-plaintext highlighter-rouge">VX</code> added to it.</p>
|
||
|
|
||
|
<p>Unlike other arithmetic instructions, this did not affect <code class="language-plaintext highlighter-rouge">VF</code> on overflow on the original COSMAC VIP. However, it seems that some interpreters set <code class="language-plaintext highlighter-rouge">VF</code> to 1 if I “overflows” from <code class="language-plaintext highlighter-rouge">0FFF</code> to above <code class="language-plaintext highlighter-rouge">1000</code>
|
||
|
(outside the normal addressing range). This wasn’t the case on the
|
||
|
original COSMAC VIP, at least, but apparently the CHIP-8 interpreter for
|
||
|
Amiga behaved this way. At least one known game, <em>Spacefight 2091!</em>, relies on this behavior. I don’t know of any games that rely on this <em>not happening</em>, so perhaps it’s safe to do it like the Amiga interpreter did.</p>
|
||
|
|
||
|
<h3 id="fx0a-get-key" class=""><code class="language-plaintext highlighter-rouge">FX0A</code>: Get key<a class="header-link" href="#fx0a-get-key" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>This instruction “blocks”; it stops executing instructions and waits for key input (or loops forever, unless a key is pressed).</p>
|
||
|
|
||
|
<p>In other words, if you followed my advice earlier and increment PC after fetching each instruction, then it should be <em>decremented</em> again here unless a key is pressed. Otherwise, PC should simply not be incremented.</p>
|
||
|
|
||
|
<p>Although this instruction stops the program from executing further
|
||
|
instructions, the timers (delay timer and sound timer) should still be
|
||
|
decreased while it’s waiting.</p>
|
||
|
|
||
|
<p>If a key is pressed while this instruction is waiting for input, its hexadecimal value will be put in <code class="language-plaintext highlighter-rouge">VX</code> and execution continues.</p>
|
||
|
|
||
|
<p>On the original COSMAC VIP, the key was only registered when it was pressed <em>and then released</em>.</p>
|
||
|
|
||
|
<h3 id="fx29-font-character" class=""><code class="language-plaintext highlighter-rouge">FX29</code>: Font character<a class="header-link" href="#fx29-font-character" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>The index register I is set to the address of the hexadecimal character in <code class="language-plaintext highlighter-rouge">VX</code>.
|
||
|
You probably stored that font somewhere in the first 512 bytes of
|
||
|
memory, so now you just need to point I to the right character.</p>
|
||
|
|
||
|
<p>An 8-bit register can hold two hexadecimal numbers, but this would
|
||
|
only point to one character. The original COSMAC VIP interpreter just
|
||
|
took the last nibble of <code class="language-plaintext highlighter-rouge">VX</code> and used that as the character.</p>
|
||
|
|
||
|
<h3 id="fx33-binary-coded-decimal-conversion" class=""><code class="language-plaintext highlighter-rouge">FX33</code>: Binary-coded decimal conversion<a class="header-link" href="#fx33-binary-coded-decimal-conversion" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>This instruction is a little involved. It takes the number in <code class="language-plaintext highlighter-rouge">VX</code>
|
||
|
(which is one byte, so it can be any number from 0 to 255) and converts
|
||
|
it to three decimal digits, storing these digits in memory at the
|
||
|
address in the index register I. For example, if <code class="language-plaintext highlighter-rouge">VX</code> contains 156 (or <code class="language-plaintext highlighter-rouge">9C</code> in hexadecimal), it would put the number 1 at the address in I, 5 in address I + 1, and 6 in address I + 2.</p>
|
||
|
|
||
|
<p>Many people seem to struggle with this instruction. You’re lucky; the
|
||
|
early CHIP-8 interpreters couldn’t divide by 10 or easily calculate a
|
||
|
number modulo 10, but you can probably do both in your programming
|
||
|
language. Do it to extract the necessary digits.</p>
|
||
|
|
||
|
<h3 id="fx55-and-fx65-store-and-load-memory" class=""><code class="language-plaintext highlighter-rouge">FX55</code> and <code class="language-plaintext highlighter-rouge">FX65</code>: Store and load memory<a class="header-link" href="#fx55-and-fx65-store-and-load-memory" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p class="notice--warning">Ambiguous instruction!</p>
|
||
|
|
||
|
<p>These two instructions store registers to memory, or load them from memory, respectively.</p>
|
||
|
|
||
|
<p>For <code class="language-plaintext highlighter-rouge">FX55</code>, the value of each variable register from <code class="language-plaintext highlighter-rouge">V0</code> to <code class="language-plaintext highlighter-rouge">VX</code> inclusive (if <code class="language-plaintext highlighter-rouge">X</code> is 0, then only <code class="language-plaintext highlighter-rouge">V0</code>) will be stored in successive memory addresses, starting with the one that’s stored in <code class="language-plaintext highlighter-rouge">I</code>. <code class="language-plaintext highlighter-rouge">V0</code> will be stored at the address in <code class="language-plaintext highlighter-rouge">I</code>, <code class="language-plaintext highlighter-rouge">V1</code> will be stored in <code class="language-plaintext highlighter-rouge">I + 1</code>, and so on, until <code class="language-plaintext highlighter-rouge">VX</code> is stored in <code class="language-plaintext highlighter-rouge">I + X</code>.</p>
|
||
|
|
||
|
<p><code class="language-plaintext highlighter-rouge">FX65</code> does
|
||
|
the same thing, except that it takes the value stored at the memory
|
||
|
addresses and loads them into the variable registers instead.</p>
|
||
|
|
||
|
<p>The original CHIP-8 interpreter for the COSMAC VIP actually incremented the <code class="language-plaintext highlighter-rouge">I</code> register while it worked. Each time it stored or loaded one register, it incremented <code class="language-plaintext highlighter-rouge">I</code>. After the instruction was finished, <code class="language-plaintext highlighter-rouge">I</code> would be set to the new value <code class="language-plaintext highlighter-rouge">I + X + 1</code>.</p>
|
||
|
|
||
|
<p>However, modern interpreters (starting with CHIP48 and SUPER-CHIP in
|
||
|
the early 90s) used a temporary variable for indexing, so when the
|
||
|
instruction was finished, <code class="language-plaintext highlighter-rouge">I</code> would still hold the same value as it did before.</p>
|
||
|
|
||
|
<p>If you only pick one behavior, go with the modern one that doesn’t actually change the value of <code class="language-plaintext highlighter-rouge">I</code>.
|
||
|
This will let you run the common CHIP-8 games you find everywhere, and
|
||
|
it’s also what the common test ROMs depend on (the other behavior will
|
||
|
fail the tests). But if you want your emulator to run older games from
|
||
|
the 1970s or 1980s, you should consider making a configurable option in
|
||
|
your emulator to toggle between these behaviors.</p>
|
||
|
|
||
|
<h2 id="troubleshooting" class="">Troubleshooting<a class="header-link" href="#troubleshooting" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h2>
|
||
|
|
||
|
<p>Your emulator is done! What’s that? Something’s not working?</p>
|
||
|
|
||
|
<p>To make your life easier, you should add some rudimentary debugging
|
||
|
capabilities. For example, you should be able to step through CHIP-8
|
||
|
instructions one by one, pausing the regular loop. You should also be
|
||
|
able to print the contents of registers and memory. That way you can
|
||
|
step through a program and see that it behaves like you expect.</p>
|
||
|
|
||
|
<p>One thing you should do is print out an error message if your
|
||
|
emulator tries to execute an unknown instruction. There aren’t many of
|
||
|
them, but if you suddenly try to execute a lot of <code class="language-plaintext highlighter-rouge">0000</code> instructions, you know you’ve somehow reached uninitialized memory.</p>
|
||
|
|
||
|
<p>Like I said before, you should start out by getting the IBM logo
|
||
|
program to run. Once you can draw to the screen properly, run one of the
|
||
|
CHIP-8 test programs you can find online. They will check your
|
||
|
instructions and tell you which ones aren’t working properly. (Note that
|
||
|
for the ambiguous instructions, they will mostly expect the “modern”
|
||
|
behavior.)</p>
|
||
|
|
||
|
<p>If you’re still stumped, you can of course ask for help in the
|
||
|
comments to this article below. There are also some great places to ask
|
||
|
for help:</p>
|
||
|
|
||
|
<ul>
|
||
|
<li><a href="https://reddit.com/r/EmuDev">/r/EmuDev on reddit</a></li>
|
||
|
<li><a href="https://discord.com/invite/7nuaqZ2">The Emulation Development Discord server</a> (there’s a #chip-8 channel)</li>
|
||
|
</ul>
|
||
|
|
||
|
<h2 id="what-next" class="">What next<a class="header-link" href="#what-next" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h2>
|
||
|
|
||
|
<p>If you’re like most people, you are now done with your obligatory
|
||
|
“Hello, world!” emulator, and are ready to tackle your dream project.
|
||
|
You could move on to emulating the Intel 8080 Space Invaders arcade
|
||
|
cabinet if you want to learn more. Or perhaps you want to make a Game
|
||
|
Boy emulator next; it has a lot more instructions and the screen drawing
|
||
|
is more complex, but it’s still not too complicated to get a lot of
|
||
|
games running.</p>
|
||
|
|
||
|
<p>But if you think CHIP-8 is an interesting platform, there are many things you could do.</p>
|
||
|
|
||
|
<h3 id="make-your-own-chip-8-game" class="active">Make your own CHIP-8 game!<a class="header-link" href="#make-your-own-chip-8-game" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>Now that you know CHIP-8’s instruction set pretty thoroughly, why not try to make a game that can run in your own emulator?</p>
|
||
|
|
||
|
<p>Every October, an annual game jam called “Octojam” is organized,
|
||
|
where people make games/programs for CHIP-8 (and SUPER-CHIP/XO-CHIP).
|
||
|
Please join us! It’s run on itch.io; <a href="https://itch.io/jam/octojam-6">here’s the page for Octojam 6 (2019)</a>.</p>
|
||
|
|
||
|
<p>Of course, you don’t need to wait until next October. Write a game any time and submit it to the <a href="https://johnearnest.github.io/chip8Archive/?sort=platform">CHIP-8 Archive</a>! You can also find los of great games to test your emulator with here.</p>
|
||
|
|
||
|
<p>Typing in raw bytes to program your game isn’t very user friendly in 2020, so most people now use <a href="http://johnearnest.github.io/Octo/">Octo</a>, a high-level assembler for CHIP-8. There are also more traditional assemblers out there.</p>
|
||
|
|
||
|
<h3 id="add-super-chip-support">Add SUPER-CHIP support<a class="header-link" href="#add-super-chip-support" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>SUPER-CHIP, which debuted on HP48 graphing calculators in 1991, makes
|
||
|
things a little less primitive. It expands the resolution to 128 x 64,
|
||
|
and adds some instructions for scrolling the display and drawing larger
|
||
|
sprites in one go.</p>
|
||
|
|
||
|
<p>It also changes the semantics of some CHIP-8 instructions, as I’ve
|
||
|
detailed above, so options for toggling that behavior (“quirks”) will be
|
||
|
a good idea. With SUPER-CHIP support, you will be able to run most
|
||
|
programs you can find scattered around the net.</p>
|
||
|
|
||
|
<p>Here’s a good quick guide to <a href="http://johnearnest.github.io/Octo/docs/SuperChip.html">Mastering Super-CHIP</a>.</p>
|
||
|
|
||
|
<h3 id="add-debug-capabilities">Add debug capabilities<a class="header-link" href="#add-debug-capabilities" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>This would make your emulator useful to two groups of people: People who develop CHIP-8 games (<a href="https://itch.io/jam/octojam-6">yes, we do exist</a>)
|
||
|
will be able to debug their games, and people who develop CHIP-8
|
||
|
emulators will be able to develop side by side with your emulator to see
|
||
|
what they’re doing wrong.</p>
|
||
|
|
||
|
<p>Debug interfaces can be very cool to make. <a href="https://twitter.com/kraptor/status/1153936421209509888">Look at this beauty!</a></p>
|
||
|
|
||
|
<p>Plus, it’ll be very useful for other emulator projects. For more
|
||
|
advaned systems, you’ll basically be doing it blind if you don’t have a
|
||
|
way to inspect your emulator’s state.</p>
|
||
|
|
||
|
<h3 id="add-xo-chip-support">Add XO-CHIP support<a class="header-link" href="#add-xo-chip-support" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>XO-CHIP is a modern extension of SUPER-CHIP. It adds two more colors,
|
||
|
advanced sound capabilities, and supports 64 kb of memory. There aren’t
|
||
|
too many XO-CHIP interpreters out there, so you could make something
|
||
|
pretty unique. <a href="http://johnearnest.github.io/Octo/docs/XO-ChipSpecification.html">Read more about XO-CHIP here.</a></p>
|
||
|
|
||
|
<h3 id="make-a-chip-8-emulator-for-an-obscure-system">Make a CHIP-8 emulator for an obscure system<a class="header-link" href="#make-a-chip-8-emulator-for-an-obscure-system" title="Permalink"><span class="sr-only">Permalink</span><i class="fas fa-link"></i></a></h3>
|
||
|
|
||
|
<p>CHIP-8 runs on everything. There’s an emulator for the SNES!</p>
|
||
|
|
||
|
<p>But maybe there’s some platform that’s missing a good emulator? Maybe
|
||
|
you want to try learning homebrew development for an old console, and
|
||
|
think CHIP-8 would be a simple experiment? What about a really good
|
||
|
ncurses emulator that you can run over SSH? Or what about a Telnet
|
||
|
server you can connect to and play CHIP-8 on? Or how about playing
|
||
|
CHIP-8 in your web browser’s inspect mode, like <a href="https://twitter.com/matthewrayfield/status/1189531704647733248">Inspect This Snake</a>?</p>
|
||
|
|
||
|
|
||
|
</section>
|
||
|
|
||
|
<footer class="page__meta">
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<p class="page__taxonomy">
|
||
|
<strong><i class="fas fa-fw fa-tags" aria-hidden="true"></i> Tags: </strong>
|
||
|
<span itemprop="keywords">
|
||
|
|
||
|
<a href="https://tobiasvl.github.io/tags/#chip-8" class="page__taxonomy-item" rel="tag">CHIP-8</a><span class="sep">, </span>
|
||
|
|
||
|
<a href="https://tobiasvl.github.io/tags/#emulation" class="page__taxonomy-item" rel="tag">Emulation</a>
|
||
|
|
||
|
</span>
|
||
|
</p>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<p class="page__date"><strong><i class="fas fa-fw fa-calendar-alt" aria-hidden="true"></i> Updated:</strong> <time datetime="2020-07-20T00:00:00+00:00">July 20, 2020</time></p>
|
||
|
|
||
|
|
||
|
</footer>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<nav class="pagination">
|
||
|
|
||
|
<a href="https://tobiasvl.github.io/blog/space-invaders/" class="pagination--pager" title="Emulating the Space Invaders look and feel
|
||
|
">Previous</a>
|
||
|
|
||
|
|
||
|
<a href="https://tobiasvl.github.io/blog/chip-8-hp-48/" class="pagination--pager" title="Running CHIP-8 on an HP 48 calculator
|
||
|
">Next</a>
|
||
|
|
||
|
</nav>
|
||
|
|
||
|
</div>
|
||
|
|
||
|
|
||
|
<div class="page__comments">
|
||
|
|
||
|
|
||
|
<h4 class="page__comments-title">Comments</h4>
|
||
|
<section id="utterances-comments"><div class="utterances" style="height: 3333px;">
|
||
|
<iframe class="utterances-frame" title="Comments" scrolling="no" src="Guide%20to%20making%20a%20CHIP-8%20emulator%20-%20Tobias%20V_files/utterances.html" loading="lazy"></iframe>
|
||
|
</div></section>
|
||
|
|
||
|
</div>
|
||
|
|
||
|
|
||
|
</article>
|
||
|
|
||
|
|
||
|
|
||
|
<div class="page__related">
|
||
|
<h4 class="page__related-title">You May Also Enjoy</h4>
|
||
|
<div class="grid__wrapper">
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<div class="grid__item">
|
||
|
<article class="archive__item" itemscope="" itemtype="https://schema.org/CreativeWork">
|
||
|
|
||
|
<div class="archive__item-teaser">
|
||
|
<img src="Guide%20to%20making%20a%20CHIP-8%20emulator%20-%20Tobias%20V_files/anchorhead_map.png" alt="">
|
||
|
</div>
|
||
|
|
||
|
<h2 class="archive__item-title no_toc" itemprop="headline">
|
||
|
|
||
|
<a href="https://tobiasvl.github.io/blog/anchorhead-map/" rel="permalink">Anchorhead map
|
||
|
</a>
|
||
|
|
||
|
</h2>
|
||
|
|
||
|
|
||
|
<p class="page__meta">
|
||
|
|
||
|
|
||
|
<span class="page__meta-date">
|
||
|
<i class="far fa-fw fa-calendar-alt" aria-hidden="true"></i>
|
||
|
|
||
|
<time datetime="2022-01-29T00:00:00+00:00">January 29, 2022</time>
|
||
|
</span>
|
||
|
|
||
|
|
||
|
<span class="page__meta-sep"></span>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<span class="page__meta-readtime">
|
||
|
<i class="far fa-fw fa-clock" aria-hidden="true"></i>
|
||
|
|
||
|
1 minute read
|
||
|
|
||
|
</span>
|
||
|
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<p class="archive__item-excerpt" itemprop="description">
|
||
|
|
||
|
A map I made for the interactive fiction game Anchorhead.
|
||
|
|
||
|
</p>
|
||
|
</article>
|
||
|
</div>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<div class="grid__item">
|
||
|
<article class="archive__item" itemscope="" itemtype="https://schema.org/CreativeWork">
|
||
|
|
||
|
<div class="archive__item-teaser">
|
||
|
<img src="Guide%20to%20making%20a%20CHIP-8%20emulator%20-%20Tobias%20V_files/hp48.png" alt="">
|
||
|
</div>
|
||
|
|
||
|
<h2 class="archive__item-title no_toc" itemprop="headline">
|
||
|
|
||
|
<a href="https://tobiasvl.github.io/blog/chip-8-hp-48/" rel="permalink">Running CHIP-8 on an HP 48 calculator
|
||
|
</a>
|
||
|
|
||
|
</h2>
|
||
|
|
||
|
|
||
|
<p class="page__meta">
|
||
|
|
||
|
|
||
|
<span class="page__meta-date">
|
||
|
<i class="far fa-fw fa-calendar-alt" aria-hidden="true"></i>
|
||
|
|
||
|
<time datetime="2020-10-13T00:00:00+00:00">October 13, 2020</time>
|
||
|
</span>
|
||
|
|
||
|
|
||
|
<span class="page__meta-sep"></span>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<span class="page__meta-readtime">
|
||
|
<i class="far fa-fw fa-clock" aria-hidden="true"></i>
|
||
|
|
||
|
8 minute read
|
||
|
|
||
|
</span>
|
||
|
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<p class="archive__item-excerpt" itemprop="description">
|
||
|
|
||
|
How to use an advanced calculator as a “Game Boy” for CHIP-8!
|
||
|
|
||
|
</p>
|
||
|
</article>
|
||
|
</div>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<div class="grid__item">
|
||
|
<article class="archive__item" itemscope="" itemtype="https://schema.org/CreativeWork">
|
||
|
|
||
|
<div class="archive__item-teaser">
|
||
|
<img src="Guide%20to%20making%20a%20CHIP-8%20emulator%20-%20Tobias%20V_files/moon_invaders.png" alt="">
|
||
|
</div>
|
||
|
|
||
|
<h2 class="archive__item-title no_toc" itemprop="headline">
|
||
|
|
||
|
<a href="https://tobiasvl.github.io/blog/space-invaders/" rel="permalink">Emulating the Space Invaders look and feel
|
||
|
</a>
|
||
|
|
||
|
</h2>
|
||
|
|
||
|
|
||
|
<p class="page__meta">
|
||
|
|
||
|
|
||
|
<span class="page__meta-date">
|
||
|
<i class="far fa-fw fa-calendar-alt" aria-hidden="true"></i>
|
||
|
|
||
|
<time datetime="2020-06-09T00:00:00+00:00">June 9, 2020</time>
|
||
|
</span>
|
||
|
|
||
|
|
||
|
<span class="page__meta-sep"></span>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<span class="page__meta-readtime">
|
||
|
<i class="far fa-fw fa-clock" aria-hidden="true"></i>
|
||
|
|
||
|
6 minute read
|
||
|
|
||
|
</span>
|
||
|
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<p class="archive__item-excerpt" itemprop="description">
|
||
|
|
||
|
My attempt at making a Space Invaders emulator look like the arcade cabinet.
|
||
|
|
||
|
</p>
|
||
|
</article>
|
||
|
</div>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<div class="grid__item">
|
||
|
<article class="archive__item" itemscope="" itemtype="https://schema.org/CreativeWork">
|
||
|
|
||
|
<div class="archive__item-teaser">
|
||
|
<img src="Guide%20to%20making%20a%20CHIP-8%20emulator%20-%20Tobias%20V_files/drom.png" alt="">
|
||
|
</div>
|
||
|
|
||
|
<h2 class="archive__item-title no_toc" itemprop="headline">
|
||
|
|
||
|
<a href="https://tobiasvl.github.io/blog/an-emulator-ui/" rel="permalink">An emulator UI
|
||
|
</a>
|
||
|
|
||
|
</h2>
|
||
|
|
||
|
|
||
|
<p class="page__meta">
|
||
|
|
||
|
|
||
|
<span class="page__meta-date">
|
||
|
<i class="far fa-fw fa-calendar-alt" aria-hidden="true"></i>
|
||
|
|
||
|
<time datetime="2020-05-31T00:00:00+00:00">May 31, 2020</time>
|
||
|
</span>
|
||
|
|
||
|
|
||
|
<span class="page__meta-sep"></span>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<span class="page__meta-readtime">
|
||
|
<i class="far fa-fw fa-clock" aria-hidden="true"></i>
|
||
|
|
||
|
5 minute read
|
||
|
|
||
|
</span>
|
||
|
|
||
|
</p>
|
||
|
|
||
|
|
||
|
<p class="archive__item-excerpt" itemprop="description">
|
||
|
|
||
|
The RetroChallenge is over, and I finished my project, the DREAM 6800 emulator DRÖM.
|
||
|
|
||
|
</p>
|
||
|
</article>
|
||
|
</div>
|
||
|
|
||
|
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
|
||
|
</div>
|
||
|
|
||
|
</div>
|
||
|
|
||
|
|
||
|
<div class="search-content">
|
||
|
<div class="search-content__inner-wrap"><form class="search-content__form" onkeydown="return event.key != 'Enter';">
|
||
|
<label class="sr-only" for="search">
|
||
|
Enter your search term...
|
||
|
</label>
|
||
|
<input type="search" id="search" class="search-input" tabindex="-1" placeholder="Enter your search term...">
|
||
|
</form>
|
||
|
<div id="results" class="results"></div></div>
|
||
|
|
||
|
</div>
|
||
|
|
||
|
|
||
|
<div id="footer" class="page__footer">
|
||
|
<footer>
|
||
|
<!-- start custom footer snippets -->
|
||
|
|
||
|
<!-- end custom footer snippets -->
|
||
|
<div class="page__footer-follow">
|
||
|
<ul class="social-icons">
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<li><a href="https://twitter.com/Spug" rel="nofollow noopener noreferrer"><i class="fab fa-fw fa-twitter" aria-hidden="true"></i> @Spug</a></li>
|
||
|
|
||
|
|
||
|
|
||
|
<li><a href="https://github.com/tobiasvl" rel="nofollow noopener noreferrer"><i class="fab fa-fw fa-github" aria-hidden="true"></i> tobiasvl</a></li>
|
||
|
|
||
|
|
||
|
|
||
|
<li><a href="https://tobiasvl.itch.io/" rel="nofollow noopener noreferrer"><i class="fab fa-fw fa-itch-io" aria-hidden="true"></i> tobiasvl</a></li>
|
||
|
|
||
|
|
||
|
|
||
|
<li><a href="https://tvil.bandcamp.com/" rel="nofollow noopener noreferrer"><i class="fab fa-fw fa-bandcamp" aria-hidden="true"></i> tvil</a></li>
|
||
|
|
||
|
|
||
|
|
||
|
<li><a href="https://instagram.com/spugster" rel="nofollow noopener noreferrer"><i class="fab fa-fw fa-instagram" aria-hidden="true"></i> spugster</a></li>
|
||
|
|
||
|
|
||
|
|
||
|
<li><a href="https://www.trueachievements.com/gamer/tobiasvl/gamecollection" rel="nofollow noopener noreferrer"><i class="fab fa-fw fa-xbox" aria-hidden="true"></i> tobiasvl</a></li>
|
||
|
|
||
|
|
||
|
|
||
|
<li><a href="https://https//www.last.fm/user/Spug" rel="nofollow noopener noreferrer"><i class="fab fa-fw fa-lastfm-square" aria-hidden="true"></i> Spug</a></li>
|
||
|
|
||
|
|
||
|
|
||
|
<li><a href="https://www.goodreads.com/user/show/11408214-tobias-langhoff" rel="nofollow noopener noreferrer"><i class="fab fa-fw fa-goodreads" aria-hidden="true"></i> Goodreads</a></li>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<li><a href="https://tobiasvl.github.io/feed.xml"><i class="fas fa-fw fa-rss-square" aria-hidden="true"></i> Feed</a></li>
|
||
|
|
||
|
</ul>
|
||
|
</div>
|
||
|
|
||
|
<div class="page__footer-copyright">© 2022 Tobias V. Langhoff. Powered by <a href="https://jekyllrb.com/" rel="nofollow">Jekyll</a> & <a href="https://mademistakes.com/work/minimal-mistakes-jekyll-theme/" rel="nofollow">Minimal Mistakes</a>.</div>
|
||
|
|
||
|
</footer>
|
||
|
</div>
|
||
|
|
||
|
|
||
|
<script src="Guide%20to%20making%20a%20CHIP-8%20emulator%20-%20Tobias%20V_files/main.min.js"></script>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<script src="Guide%20to%20making%20a%20CHIP-8%20emulator%20-%20Tobias%20V_files/lunr.min.js"></script>
|
||
|
<script src="Guide%20to%20making%20a%20CHIP-8%20emulator%20-%20Tobias%20V_files/lunr-store.js"></script>
|
||
|
<script src="Guide%20to%20making%20a%20CHIP-8%20emulator%20-%20Tobias%20V_files/lunr-en.js"></script>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||
|
<script async="" src="Guide%20to%20making%20a%20CHIP-8%20emulator%20-%20Tobias%20V_files/js"></script>
|
||
|
<script>
|
||
|
window.dataLayer = window.dataLayer || [];
|
||
|
function gtag(){dataLayer.push(arguments);}
|
||
|
gtag('js', new Date());
|
||
|
|
||
|
gtag('config', 'UA-37898375-14', { 'anonymize_ip': false});
|
||
|
</script>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
<script>
|
||
|
'use strict';
|
||
|
|
||
|
(function() {
|
||
|
var commentContainer = document.querySelector('#utterances-comments');
|
||
|
|
||
|
if (!commentContainer) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var script = document.createElement('script');
|
||
|
script.setAttribute('src', 'https://utteranc.es/client.js');
|
||
|
script.setAttribute('repo', 'tobiasvl/tobiasvl.github.io');
|
||
|
script.setAttribute('issue-term', 'og:title');
|
||
|
script.setAttribute('theme', 'github-light');
|
||
|
script.setAttribute('crossorigin', 'anonymous');
|
||
|
|
||
|
commentContainer.appendChild(script);
|
||
|
})();
|
||
|
</script>
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
</body></html>
|