<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: zaiqltd</title>
    <description>The latest articles on DEV Community by zaiqltd (@zaiqltd).</description>
    <link>https://dev.to/zaiqltd</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3971614%2F1ca25414-21df-402d-b680-69b3a5467a9d.png</url>
      <title>DEV Community: zaiqltd</title>
      <link>https://dev.to/zaiqltd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zaiqltd"/>
    <language>en</language>
    <item>
      <title>How we built a gate-accurate Game Boy emulator in Rust (and got dmg-acid2 pixel-perfect)</title>
      <dc:creator>zaiqltd</dc:creator>
      <pubDate>Sat, 06 Jun 2026 20:18:07 +0000</pubDate>
      <link>https://dev.to/zaiqltd/how-we-built-a-gate-accurate-game-boy-emulator-in-rust-and-got-dmg-acid2-pixel-perfect-31l</link>
      <guid>https://dev.to/zaiqltd/how-we-built-a-gate-accurate-game-boy-emulator-in-rust-and-got-dmg-acid2-pixel-perfect-31l</guid>
      <description>&lt;p&gt;We are Zaiq, an engineering studio. We built &lt;strong&gt;Revenant&lt;/strong&gt;, a Game Boy and Game Boy Color emulator, from scratch in Rust, compiled to WebAssembly, with a playable arcade that runs in your browser. No emulation libraries: every chip is written by hand.&lt;/p&gt;

&lt;p&gt;Play it right now: &lt;strong&gt;&lt;a href="https://zaiqltd.github.io/revenant/" rel="noopener noreferrer"&gt;https://zaiqltd.github.io/revenant/&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
Code and the full accuracy scorecard: &lt;strong&gt;&lt;a href="https://github.com/zaiqltd/revenant" rel="noopener noreferrer"&gt;https://github.com/zaiqltd/revenant&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is what we built, and what "accurate" actually means.&lt;/p&gt;

&lt;h2&gt;
  
  
  "It runs Pokemon" is the wrong bar
&lt;/h2&gt;

&lt;p&gt;Most emulators clear one bar: a game boots and looks roughly right. That is the easy 90%. The interesting part is the last 10%, the timing edge cases real cartridges depend on, the ones that only show up when you emulate the machine on its own 4.194304 MHz clock, cycle by cycle.&lt;/p&gt;

&lt;p&gt;So we measured ourselves against the bar the hardware sets for itself: the community's test ROMs. The headline result: &lt;strong&gt;dmg-acid2 renders pixel-perfect, 0 of 23040 pixels different from real hardware&lt;/strong&gt;, on both the original DMG and the Game Boy Color. We currently pass &lt;strong&gt;130 of 279&lt;/strong&gt; of the canonical accuracy gates, and the full scoreboard is in the repo so anyone can check.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CPU: stepped one T-cycle at a time
&lt;/h2&gt;

&lt;p&gt;The SM83 core is not just a set of opcodes, it is a set of opcodes with precise sub-instruction timing. Reads and writes land on specific cycles within an instruction, and peripherals see those accesses as they happen, not batched at the end.&lt;/p&gt;

&lt;p&gt;So Revenant steps the CPU one T-cycle at a time and advances the rest of the machine in lockstep. That is more work than the common "run the whole instruction, then total the cycles" approach, but it is the only way to get the halt bug, interrupt timing, and the PPU interactions right.&lt;/p&gt;

&lt;h2&gt;
  
  
  The PPU: a real pixel FIFO, not a scanline blit
&lt;/h2&gt;

&lt;p&gt;The shortcut for graphics is to render a whole scanline at once. It is simple, and it is wrong: it cannot reproduce mid-scanline register changes, which real games and every serious test ROM use.&lt;/p&gt;

&lt;p&gt;Revenant implements the actual pixel FIFO: background and sprite pixels are fetched and shifted out one at a time, with the fetcher and the LCD controller modelled as the state machines they are on hardware. That is what makes dmg-acid2, the PPU's torture test, come out pixel-perfect.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rest of the machine
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;4-channel APU&lt;/strong&gt; (two pulse channels, wave, noise), so the games have real sound.&lt;/li&gt;
&lt;li&gt;The cartridge mappers: &lt;strong&gt;MBC1, MBC2, MBC3, MBC5&lt;/strong&gt;, including the MBC3 real-time clock.&lt;/li&gt;
&lt;li&gt;Full &lt;strong&gt;Game Boy Color&lt;/strong&gt; support: double-speed mode, HDMA, and the colour palettes.&lt;/li&gt;
&lt;li&gt;Battery saves persist in the browser, per cartridge.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Shipping it to the browser
&lt;/h2&gt;

&lt;p&gt;The core is plain Rust compiled to WebAssembly, so the same code that passes the test ROMs in a headless harness also runs the arcade in your browser at full speed. On top we put a live &lt;strong&gt;CPU and PPU debugger&lt;/strong&gt; that ticks alongside the running game, and instruction-level &lt;strong&gt;rewind&lt;/strong&gt;, so you can step the machine backwards when something looks wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The arcade has zero copyrighted content
&lt;/h2&gt;

&lt;p&gt;We did not want a demo that asks you to "go find a ROM." So we wrote a tiny SM83 assembler (an original 8x8 font, APU blip helpers) and hand-assembled &lt;strong&gt;11 original homebrew games&lt;/strong&gt;: Snake, Breakout, Blocks, Flap, Blaster, Pong, Crosser, Maze, Memory, Dodge, and the first thing the emulator ever drew, a movable smiley. Each has a title screen, a score, a game-over screen, and sound. Or drop in your own .gb / .gbc file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why we built it
&lt;/h2&gt;

&lt;p&gt;Not for a client. We built it because the team that can emulate a 1989 console at the cycle level is the team you want on your hardest problem. That is the standard we hold at Zaiq, and we aim it at real business problems, with AI as the edge.&lt;/p&gt;

&lt;p&gt;Play Revenant: &lt;a href="https://zaiqltd.github.io/revenant/" rel="noopener noreferrer"&gt;https://zaiqltd.github.io/revenant/&lt;/a&gt;&lt;br&gt;
If you have a hard problem, bring it: &lt;strong&gt;&lt;a href="https://zaiq.co.za" rel="noopener noreferrer"&gt;https://zaiq.co.za&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>opensource</category>
      <category>rust</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
