• Stars
    star
    413
  • Rank 104,399 (Top 3 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created almost 6 years ago
  • Updated over 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

๐ŸŽฎ โ€Ž A Chip-8 emulator written in JavaScript for web, CLI, and native UI.

Chip8.js

License: MIT chip8js on NPM Build Status Coverage Status

A Chip-8 emulator written in JavaScript.

Chip-8 is a simple, interpreted, programming language which was first used on some do-it-yourself computer systems in the late 1970s and early 1980s.

View the demo | Read the article

Table of Contents

Installation

This guide assumes you already have Node.js and npm installed.

Prior to installing Chip8.js, you must have CMake installed.

brew install cmake

Clone the repository and install.

git clone [email protected]:taniarascia/chip8.git
cd chip8
npm i

Usage

Chip8.js can be run on the web, in a terminal, or using native keybindings.

Web

Development

Spin up a local server during development.

# watch for changes and rebuild
npm run watch:web

# spin up server on localhost:8080
cd web && http-server 

Deployment

Build and bundle the code for the web.

npm run build:web

Deploy to GitHub.

# remove web/bundle.js from .gitignore
git add web && git commit -m "update web version"

# delete gh-pages branch from origin before push
git subtree push --prefix web origin gh-pages

Terminal

Run Chip8.js in the terminal by selecting a ROM.

npm run play:terminal roms/<ROM>

Native

Run Chip8.js natively with raylib (experimental).

npm run play:native roms/<ROM>

Motivation

Chip8.js is a project to write a Chip-8 emulator in JavaScript. The main motivation is to learn lower level programming concepts and to increase familiarity with the Node.js environment.

Here are some of the concepts I learned while writing this program:

  • The base system: specifically base 2 (binary), base 10 (decimal), base 16 (hexadecimal), how they interact with each other and the concept of abstract numbers in programming
  • Bits, nibbles, bytes, ASCII encoding, and big and little endian values
  • Bitwise operators - AND (&), OR (|), XOR (^), left shift (<<), right shift (>>) and how to use them for masking, setting, and testing values
  • Using the Node built-in file system (fs)
  • The concept of a raw data buffer and how to work with it, how to convert an 8-bit buffer to a 16-bit big endian array
  • Writing and understanding a 8-bit and 16-bit hex dump
  • How to disassemble and decode an opcode into instructions a CPU can use
  • How a CPU can utilize memory, stack, program counters, stack pointers, memory addresses, and registers
  • How a CPU implements fetch, decode, and execute

And here are some articles I wrote based on those concepts:

Testing

The unit tests for Chip8.js use the Jest testing framework. You can run all test suites with or without displaying coverage.

# Run test suites
npm run test

# Run test suites and view coverage
npm run test --coverage

Chip8.js has two suites of unit tests:

  • Opcode instruction masks and arguments
  • CPU implementation of instructions

Instruction tests

The instruction tests cover the INSTRUCTION_SET found in data/instructionSet.js. Each instruction has:

  • A key: for internal use
  • An id: for a unique name
  • A name: for the type of instruction)
  • A mask: to filter out arguments from instruction signifiers)
  • A pattern: to match the mask to the specific instruction pattern
  • arguments, each of which contain:
    • A mask: to filter the nibble(s) to arguments
    • A shift: to shift it by location
    • A type: to signify the type of argument
// data/instructionSet.js

{
  key: 6,
  id: 'SE_VX_NN',
  name: 'SE',
  mask: 0xf000,
  pattern: 0x3000,
  arguments: [{ mask: 0x0f00, shift: 8, type: 'R' }, { mask: 0x00ff, shift: 0, type: 'NN' }],
}

Each unit test checks an opcode to an instruction and tests:

  • The unique id to ensure the correct instruction is running for the mask/pattern
  • The number of arguments
  • The value of the arguments
// tests/instructions.test.js

test('6: Expect disassembler to match opcode 3xnn to instruction SE_VX_NN', () => {
  expect(Disassembler.disassemble(0x3abb).instruction).toHaveProperty('id', 'SE_VX_NN')
  expect(Disassembler.disassemble(0x3abb).args).toHaveLength(2)
  expect(Disassembler.disassemble(0x3abb).args[0]).toBe(0xa)
  expect(Disassembler.disassemble(0x3abb).args[1]).toBe(0xbb)
})

There are 35 instruction tests for 35 opcodes (the first instruction, CLS, is no longer implemented).

CPU tests

The CPU decodes the opcode and returns the instruction object from data/instructionSet.js. Each instruction performs a specific, unique action in the case. The CPU tests test the state of the CPU after an executing an instruction.

In the below example, the instruction is skipping an instruction if Vx === nn, otherwise it's going to the next instruction as usual.

// classes/CPU.js

case 'SE_VX_NN':
  // Skip next instruction if Vx = nn.
  if (this.registers[args[0]] === args[1]) {
    this._skipInstruction()
  } else {
    this._nextInstruction()
  }
  break

Each CPU test:

  • Loads a RomBuffer containing the data of a single opcode
  • Sets up the state to make the instruction testable (if necessary)
  • Executes the step method
  • Tests all possible outcomes of an instruction and state updates

In this example, the instruction can either be skipped or not skipped depending on the arguments, and both cases are tested.

// tests/cpu.test.js

test('6: SE_VX_NN (3xnn) - Program counter should increment by two bytes if register x is not equal to nn argument', () => {
  cpu.load({ data: [0x3abb] })
  cpu.step()

  expect(cpu.PC).toBe(0x202)
})

test('6: SE_VX_NN (3xnn) - Program counter should increment by four bytes if register x is equal to nn argument', () => {
  cpu.load({ data: [0x3abb] })
  cpu.registers[0xa] = 0xbb

  cpu.step()

  expect(cpu.PC).toBe(0x204)
})

Acknowledgements

Author

License

This project is open source and available under the MIT License.

More Repositories

1

takenote

๐Ÿ“ โ€Ž A web-based notes app for developers.
TypeScript
6,824
star
2

webpack-boilerplate

๐Ÿ“ฆ โ€Ž A sensible webpack 5 boilerplate.
JavaScript
2,399
star
3

taniarascia.com

๐Ÿ’พ โ€Ž Personal website running on Gatsby, React, and Node.js.
JavaScript
1,982
star
4

wp-functions

A compilation of function snippets for WordPress developers who create their own themes.
1,206
star
5

new-moon

๐ŸŒ™ โ€Ž The optimized dark theme for web development.
Less
1,205
star
6

primitive

โ›๏ธ โ€Ž A front-end design toolkit for developing web apps.
SCSS
920
star
7

react-tutorial

A walkthrough of basic React concepts.
CSS
738
star
8

mvc

A simple MVC application in plain JavaScript.
JavaScript
575
star
9

sandbox

Development sandbox for front end projects and tutorials.
JavaScript
531
star
10

react-hooks

Build a CRUD app in React with Hooks.
JavaScript
371
star
11

laconia

๐Ÿบ โ€Ž A minimalist MVC framework.
PHP
360
star
12

snek

๐Ÿ โ€Ž A terminal-based Snake implementation written in JavaScript.
JavaScript
272
star
13

pdo

Connecting to MySQL in PHP using PDO.
PHP
230
star
14

startwordpress

Learn how to develop a WordPress theme from scratch with this basic skeleton and accompanying tutorial.
PHP
208
star
15

chat

๐Ÿ’ฌ ๐Ÿ• โ€Ž very chat. such messages. so talking. wow. React/Redux, TypeScript, Socket.io chat app.
TypeScript
204
star
16

accordion

๐Ÿช— Play the accordion with your computer keyboard!
JavaScript
174
star
17

vue-tutorial

A walkthrough of basic Vue concepts.
Vue
149
star
18

react-advanced-form

An example of a schema-based form system for React.
JavaScript
128
star
19

oblate

Custom theme for my personal website and blog.
PHP
124
star
20

startjekyll

An example and guide to getting started with Jekyll and static site generators.
CSS
115
star
21

memory

โญ โ€Ž JavaScript Memory Game.
JavaScript
110
star
22

node-api-postgres

RESTful API with Node.js, Express, and Postgres.
JavaScript
103
star
23

upload

How to Upload a File to a Server in PHP
PHP
101
star
24

bootstrapblog

Build on the official Bootstrap blog starter template to learn how to make a WordPress theme.
HTML
97
star
25

sokoban

Sokoban.js ๐Ÿ“ฆ
JavaScript
91
star
26

new-moon-vscode

New Moon Theme for Visual Studio Code.
90
star
27

untheme

A blank WordPress theme for developers.
PHP
88
star
28

new-moon-chrome-devtools

New Moon Theme for Chrome Devtools.
CSS
58
star
29

card

A well-designed card element.
CSS
55
star
30

new-moon-sublime

New Moon Syntax Theme for Sublime Text
54
star
31

router-example

Use React Router DOM to create a Single Page Application (SPA).
JavaScript
52
star
32

tictactoe

#๏ธโƒฃ Tic Tac Toe in TypeScript.
TypeScript
42
star
33

baba

JavaScript
31
star
34

node-test

How to make your first Node.js project
JavaScript
26
star
35

new-moon-atom-syntax

New Moon Syntax Theme for Atom
CSS
25
star
36

new-moon-brackets

New Moon Theme for Brackets.
Less
22
star
37

calc

Unit Testing in JavaScript
JavaScript
20
star
38

graphql-fantasy-api

JavaScript
19
star
39

dotfiles

Dotfile configuration.
15
star
40

taniarascia

13
star
41

singularity

An online, text-based dystopian strategy game built in PHP. Modified from the original QMT Promisance code.
PHP
12
star
42

3d

3D printer projects.
10
star
43

coffee

Cafรฉtography
JavaScript
10
star
44

new-moon.vim

port of taniarascias newmoon colorscheme
Vim Script
10
star
45

startgrunt

Learn how to install Grunt and use it to create a Sass and JavaScript workflow.
JavaScript
10
star
46

comments

Comments
7
star
47

httpcast

HTML
5
star
48

signals

Signal test
JavaScript
3
star