Git Product home page Git Product logo

torch2424 / wasmboy Goto Github PK

View Code? Open in Web Editor NEW
1.4K 22.0 63.0 104.6 MB

Game Boy / Game Boy Color Emulator Library, ๐ŸŽฎwritten for WebAssembly using AssemblyScript. ๐Ÿš€Demos built with Preact and Svelte. โš›๏ธ

Home Page: https://wasmboy.app/

License: GNU General Public License v3.0

JavaScript 15.24% TypeScript 27.45% WebAssembly 57.31%
gameboy preact gameboy-color assemblyscript emulator web-assembly gameboy-emulator webassembly wasm

wasmboy's Introduction

wasmboy

Build Status npm version npm bundle size (minified) wapm version npm GitHub

๐ŸŽฎ๐Ÿ‘พ๐Ÿ•น๏ธ Gameboy Emulator Library written in Web Assembly using AssemblyScript, Demos in Preact and Svelte ๐ŸŽฎ๐Ÿ‘พ๐Ÿ•น๏ธ

Project is still < 1.0.0. Most games are playable, but the emulator is still not very accurate. Expect bugs.

Core/Lib Documentation

Talk given at WebAssembly SF March 28th, 2019

Pokemon Crystal Wasmboy Debugger Demo

Table of Contents

Features

  • Emulates the Gameboy / Gameboy Color ๐ŸŽฎ๐Ÿ‘พ๐Ÿ•น๏ธ
  • Outputs graphics to a scalable / responsive HTML5 canvas ๐Ÿ–ผ๏ธ, and audio through the Web Audio API ๐Ÿ”Š
  • Support for In-game saves, and save states ๐Ÿ’พ
  • Configurable options to increase performance for low(er) end devices ๐Ÿ”ฅ
  • Importable into other projects as a dependency โ™ป๏ธ
  • Built with Web Assembly ๐Ÿ•ธ๏ธ
  • Uses Web Workers for parallelized rendering ๐Ÿ› ๏ธ
  • Keyboard and gamepad input support using responsive gamepad โŒจ๏ธ ๐ŸŽฎ
  • Debugger with a value table (I/O map), Tile Data visualizer, and Background Map with Scroll Indicators ๐Ÿ›
  • Runs in both Browser and Node ๐ŸŒ

Usage

Project is still < 1.0.0. Most games are playable, but the emulator is still not very accurate. Expect bugs.

1.0 Roadmap Tracking Issue

Simply install through npm:

npm install --save wasmboy

Documentation for the project can be found on the WasmBoy Wiki.

Supported Platforms

Try to test and aim for support on all major browsers (Chrome, Firefox, and Safari). Also, Node support works with the headless option in the WasmBoy config, and using the Worker Threads --experimental-worker flag.

In-Game Screenshots

Gameboy Support

Is that a demo in your pocket Megaman 2 Pokemon Blue tetris tobu tobu girl

Gameboy Color Support

Links Awakening L s d j Megaman extreme 2 Pokemon Silver Pokemon Yellow back to color demo

Demo Applications

Debugger

Application Link

A full debugger meant for analyzing the internals of the gameboy. Great for HomeBrew Gameboy Development, or using as a reference point for building your own GameBoy emulator. See the gif at the top of the README for an example.

Features

  • Support of all Gameboy Components: CPU, PPU (Graphics), APU (Audio), Memory, Interrupts, and Timers. ๐ŸŽฎ
  • Per cycle state of each Game Boy components data, internal registers, and relevant memory addresses. ๐ŸŒ
  • Loaded ROM Information and parsing of the Cartridge Header. ๐Ÿ’พ
  • CPU Control options. Stepping per opcode, and breakpoints. ๐Ÿง 
  • Graphics Background Map, with border for current "camera" location with respect to scroll registers. ๐Ÿ–ผ๏ธ
  • Graphics Tile Data, to display the loaded tiles currently loaded across all VRAM Banks. ๐ŸŽจ
  • WasmBoy Control options. Play, Pause, Save State, and Load State. โฏ๏ธ ๐Ÿ“š
  • Ability to log the entire WasmBoy Library Object and Memory to the DevTools Console. ๐Ÿ–ฅ๏ธ
  • Highly productive "Docker" layout, with snapping of widgets onto sections of the screen and tab support. โš“
  • Saved Layouts between sessions. ๐Ÿ’ 
  • Help widget with tips on how to be effective in the debugger. ๐Ÿ™‹

Mobile Demo

For UI/UX reasons, on mobile the debugger is simply a web app for testing the lib. This is useful for testing a ROM on the go. For playing games, I would suggest VaporBoy. Below is an example of the mobile demo:

Pokemon Crystal Wasmboy Mobile Demo

Anaytics / Privacy

Analytics Wrapper Service

Analytics is used on this application simply for performance monitoring, and tracking popularity of the applications. The following events are sent, with nothing more than the event name. The analytics provider used is Google Analytics.

  • Whenever a new ROM is loaded, and played for the first time.
  • Whether attempting to load a ROM was successful.
  • Whenever a state is saved.
  • Whenever a state is loaded.
  • Whenever custom WasmBoy options are applied.
  • Whenever the Google Drive option is selected.
  • Whenever the mobile demo is manually reloaded.

Benchmark

Application Link

Medium Article

Since WasmBoy is built in AssemblyScript, it can also run it's core through the Typescript compiler if we mock out some of the WebAssembly interface. The benchmarking tool was built as a way to compare WebAssembly performance to Javascript / ES6 performance, after compiling the core to both WebAssembly and Javascript. It includes detailed stats, live running output, and multiple graphs. Also great for comparing the performance of devices that run WasmBoy.

Example

WasmBoy Benchmark Runner Section on Safari

Anaytics / Privacy

Analytics is used on this application simply for performance monitoring, and tracking popularity of the application. The following events are sent, with nothing more than the event name. The analytics provider used is Google Analytics.

  • Whenever a new ROM is loaded from the particular source.
  • Whenever the benchmark is ran.
  • Whenever results are rendered for the benchmark.

Iframe Embed

An Iframe embeddable version of WasmBoy. Simply provide information through URL Query Params, and embed a ROM on your website! Great for embedding your HomeBrew Game Boy / Game Boy Color games on your website, (WordPress) blog, and game hosting services such as itch.io.

Example

Example Tobu Tobu Girl, Homebrew Hub Iframe

Gif of the Tobu Tobu Girl, Home brew hub example

Usage

Add an iframe to your website like the following:

<iframe title="WasmBoy Iframe Embed" width="160" height="144" allowfullscreen="true" src="https://wasmboy.app/iframe/?[QUERY_PARAMS_GO_HERE]"> </iframe>

The iframe is configured by adding URL Query Params. The configuration params are:

  • rom-url - (Required) The URL to the .gb or .gbc ROM that will be loaded, fetched, and played.
  • rom-name - The name of the ROM being played.
  • play-poster - The URL to the image shown at the intial "click to play", play poster.

Please ensure all assets that are being loaded by the iframe embed, such as ROMs and images, will work with CORS. The WasmBoy Iframe Embed will take the full width and height (100%) of it's iframe container. Thus, it will be up to your styling to ensure the iframe preserves the GameBoy 160x144 resolution.

Anaytics / Privacy

Analytics is used on this application simply for performance monitoring, and tracking popularity of the application. The analytics provider used is Google Analytics. Only basic user visit data is recorded / used.

Tests

These are all currently known passing tests (by me), there may be more test roms out there that pass. Some tests may not pass, and that can either be because of the component it is testing is actually incorrect, or another component that the test is testing is not yet implemented, or is incorrect (e.g a lot of mooneye tests rely on Serial Interrupts, which this emulator has yet to implement). Feel free to open an issue or PR to add any more passing tests to this list ๐Ÿ˜„ . The test names are listed from left to right, top to bottom.

Blarrg

Repo with all blargg's tests and source

cpu_instrs, instr_timing, mem_timing, mem_timing-2, halt_bug, cgb_sound

Cpu Instructions all tests passing Instruction timing all tests passing Memory timing all tests passing Memory timing 2 all tests passing halt bug all tests passing cgb sound all tests passing

Mooneye

Mooneye GB Emulator / Tests

Timing

div_write, rapid_toggle, tim00, tim00_div_trigger, tim01, tim01_div_trigger, tim10, tim10_div_trigger, tim11, tim11_div_trigger, tima_reload, tima_write_reloading, tma_write_reloading

div write test passing rapid toggle test passing tim00 test passing tim00 div trigger test passing tim01 test passing tim01 div trigger test passing tim10 test passing tim10 div trigger test passing tim11 test passing tim11 div trigger test passing tima reload test passing tima write reloading test passing tma write reloading test passing

Halt

halt_ime0_ei, halt_ime0_nointr_timing, halt_ime1_timing

halt_ime0_ei test passing halt_ime0_nointr_timing test passing halt_ime1_timing test passing

Contributing

Feel free to fork and submit PRs! Opening an issue is reccomended before starting any development, as a discussion would be nice on the idea / feature before writing code. Any help is much appreciated, and would be a ton of fun!

Installation

Just your standard node app. Install Node with nvm, git clone the project, and npm install, and you should be good to go!

CLI Commands / Npm Scripts

The project contains three different elements.

  • The core or wasm which is the web assembly module for wasmboy written in AssemblyScript.
  • The lib which is the importable library of wasmboy that can be used in other projects, that adds a top level API to the core.
  • The demo, which is a collection of different apps that are used for demoing purposes of the lib and core.

Most of the build process in this project is done using Rollup.js. Each element / component of the project is configured in its own rollup.*.js file, and are then all used within the standard rollup.config.js file by the rollup CLI. Also, The core wasm uses the AssemblyScript compiler CLI tool.

Commands for each part of the project will be prepended with their element name and a colon, e.g debugger:[command here].

Common command parts are:

  • dev / watch - How the project should be served and developed with tools like reloading.
  • build - Make production builds of the component / element of the project.

Commands not prepended with a colon are meant for easily building on all of the different parts as a whole.

Not all commands are documented, only ones relevant to making changes to the library for contributions. * represents the category of commands, and is not an actual command.

# Command to serve the project, and watch the debugger, wasm, and lib for changes
# Uses concurrently: https://github.com/kimmobrunfeldt/concurrently
# Concurrently helps cleanup the output and organizes watchers on commands that require concurrent tools

# Serve the general project for development (Watches the core, lib, and debugger)
npm run start

# Same as npm start
npm run dev

# Same as npm start
npm run watch

# Build everything to be ready to be pushed to npm or released
npm run build

# Linting commands used during precommit an tests
npm run prettier:*

# Commands for building/serving the core, offers commands for building with the Assemblyscript Compiler (WASM) or Typescript (JS)
npm run core:*

# Commands for building/serving the JS lib
npm run lib:*

# Run tests in `test/accuracy/test.js`
npm run test

# Run tests in `test/performance/test.js`
npm run test:performance

# All commands for testing, and are test related
npm run test:*

# Commands for the building / serving the debugger
npm run debugger:*

# Commands for building / serving the benchmark tool
npm run benchmark:*

# Commands for building / serving all available apps in wasmboy
npm run demo:*

Using the gh-pages for debugger/demo deployment onto gh-pages.

Notable Projects

  • VaporBoy - PWA for playing ROMs with WasmBoy!

  • wasmboy-rs - Wasmboy Compiled to Rust, for native executables and additional cool features!

  • wasmboy.py - Wasmboy running in Python!

Special Thanks

Resources

wasmboy's People

Contributors

cheriejw avatar dcodeio avatar dependabot[bot] avatar issotm avatar malax avatar maxgraey avatar syrusakbary avatar tkers avatar torch2424 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wasmboy's Issues

Fix Some More Performance Issues

We lost a lot of speed in running the emu since b49f76f .

After doing some research, the PR #38 was not the culprit, but rather #40 , I suspect that doing all the jumping between JS and Wasm to grab constants is adding a huge overhead, so we should simply cache these constants in function calls on initialize :).

Should also investigate PRs beyond #38 as well

Fix Audio Bugs/TODOs

  • Channel 1 sweep sometimes starts way too low. For instance, try jumping down a cliff in Links Awakening 2.
  • Channel 4 sounds a little too spray-y like almost if the noise is fanned out. Also, lightning isn't very loud in links awakening 2, but waves are.
  • Audio starts on all games very loud with a random noise.
  • A lot of TODOs, Especially applying master volume
  • Audio Has trouble keeping up

Write some Performance Tests

Create a seperate set of tests that can run the gameboy, and test how long it takes to run X frames on Y rom.

Demos are good because they don't require input.

Such as the "Demo in your pocket", and the awesome-gb dudes recommended "Demotronic"

Wasmboy Game Sav RAM and Save States

Identify Gameboy games and rooms by their header (either titles or checksums)

http://gbdev.gg8.se/wiki/articles/Gameboy_ROM_Header_Info

https://www.google.com/amp/s/amp.reddit.com/r/EmuDev/comments/6bettn/list_of_all_gbgbc_rom_cartridge_information_with/

Read that catridge ram is battery powered. May just want to save the catridge ram in memory. Which equates to about 50 games of ram being able to be saved in memory :)

http://gbdev.gg8.se/wiki/articles/Memory_Bank_Controllers#A000-BFFF_-_RAM_Bank_00-03.2C_if_any_.28Read.2FWrite.29

https://developers.google.com/web/fundamentals/instant-and-offline/web-storage/offline-for-pwa

https://developers.google.com/web/fundamentals/app-install-banners/

Ionic handles app resources caching we just gotta save save files again pico deploy style with idb-keyval, which supports saving arrays and objects :)

https://www.google.com/amp/s/blog.ionicframework.com/how-to-make-pwas-with-ionic/amp/

Gameplan / Roadmap for Beta MVP

  • Run the bootrom, get some pixels drawn, and scroll the logo
  • Code Cleanup
  • Make a more legit debugger
  • Run the cpu_instructs test rom, and fix bugs
  • Move opcode feeding into wasm. And have js poll for when it should render. (Maybe a flag in memory?)
  • Get Tetris to play
  • Wasmboy memory map
  • Rom Banking
  • Joypad support
  • Fix Graphical Bugs
  • Get Sound
  • Get In-game saves (Cartridge RAM -> IndexedDB)
  • Get Save States (Everything -> IndexedDB)
  • Beta Gameboy Color Support
  • Cry tears of happiness
  • More Optional Performance Hacks
  • Code Cleanup
  • Update the README
  • Get ready for publish to npm
  • Publish to npm
  • Make "frontends" for the Wasmboy lib
  • Improve Accuracy / More Test Roms (With maybe some help from the community? :) )

Find a way to efficiently scale wasm memory

As suggested by ISSOtm:

Possible allocation strategy :

  • Allocate one page
  • Dump ROM0 and ROM1, which always exist, in the first 32kB
  • Check cart header
  • Grow() accordingly, and dump ROM
  • Grow() by one page for the rest of the memory (2 pages if it turns out more is needed, though)
    (Btw, 1 page spans 4 ROM banks)

After referencing the Wasmboy memory map

Joypad interrupt resets tetris

It is quite odd, and can't seem to figure out why. As Joypad interrupts happen whenever a button is pressed. And in Dr. Mario, the interrupt causes an opcode that doesn't exist :p

Rename the `wasm` folder to `core`

It makes more sense this way in the whole architecture of the application. and makes it easier to distinguish between the "frontend Js lib api", and the "backend web assembly core"

Optimization Ideas

Optimizing has been a ton of fun. But here's what I'm learning (shoutout to @binji):

Ask yourself these things:

"What can I pull out of the main loop?"
"What can I assume will not change?"
"What can I assume has not changed until a write to memory?"
"What can be cached to speed up.individual loops?"

Some Quick ideas:

  • Interrupts enabled/requested registers. If both are less than or equal too zero, skip.

  • Tile caching. Would require Assembly script maps to be completed. Could cache tiles, and discard them if we find that they changed.

  • Add more checks in memory.

Watch the ultimate Gameboy talk, with performance in mind

Wasmboy Sound, exploring web audio

Expose the memory map constants to JS and Rust

By exporting the constants making up the memory map, both the JS and Rust emulator can just make use of the AssemblyScript constants.

I just tested it and you can just export them as such:

export const BLA: usize = 5;
(global $BLA (export "BLA") i32 (i32.const 5))

Wasmboy Builds

Need to use Rollup Which not only does cool tree shaking and stuff, but I guess is the best way to build ES6 modules, for both browsers and node :)

And then also need to use Rollup Wasm and probably some other plugins

Notable Games with Issues

This issue is not a general compatibility table, but for now, is just a personal reference of games that do or do not work to help with general compatibility and in determining beta vs. stable status of the core in general

Compatibility Notes

  • Donkey Kong Country - Really messed up graphically, and can't get past the level select screen without crashing. The game tries to do an OAM within 0xFFXX, but IO am assuming it does not correctly get written and breaks. Fixed with #75

  • Bionic Commando - Sound does some weirdness, game play fine however

  • GBC Spongebob - Level Background loads incorrectly, and looks super weird

  • Wario Land 3 - LYC is checked too late, and Palettes are messed up

  • Crystalis - Same situation as bionic commando

  • Kirby's Dreamland - We get an opcode crash after the first level intro cutscene. Was a timing issue, fixed with #193

  • Link's Awakening - Intro "Cha-Ching" is incorrect. Thanks @Malax ๐Ÿ˜„

Frontend shouldn't need to grow the WASM Memory

This commit changed the memory base to 0, causing it to only preallocate 1 page: eec0552

JS / Rust shouldn't need to grow the memory though. This can either be changed back or AssemblyScript can just grow the memory itself. This also means that the call can be removed in JS altogether.

Improve Performance tests more

Need to do some logging to make sure that we are passing the correct configuration params.

Also, may want to run an (3 runs per option) average, because I am noticing that results can vary kind of wildly at times.

Build a Priority map in Memory for Sprites and GBC BG/Win

So, the only good way I could think of handling the Sprite vs. BG/Window priority weirdness, was to keep track of what we drew on our Bg/Window Layer.

So, we need to update the memory map for a 160 x 144 2d array type thing, where 1 byte represents one pixel.

Bits 0 & 1 will represent the color Id drawn by the BG/Window
Bit 2 will represent if the Bg/Window has GBC priority.

Not going to do this per tile, juuusssttt in case there is some craziness that can happen in between drawing a tile

Write Documentation for the JS Lib API and the Core API

Also related to #65

Since we are about to start wrapping things up. We should try to write docs for the API that we should have, and then refactor the code accordingly. That way we can get some other eyes on the API, and names and things, and then implement all at once.

The old current API, can be preserved in the index.ts, by exporting the new API with the old naming :)

Also, decided to use github wikis for docs. Since, it is probably most well know, git books are kind of confusing for me to navigate (personally), and doing the monolithic/documentation directory approach
that create-reat-app follows is kind of awkward for navigating, and sometimes finding things.

Link Cable Emulation

Look into Link Cable Emulation

Goal would to be have it done over WebRtc with a peer to peer connection, using something like simple-peer or PeerJs

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.