Open-source project
floooh/chips avatar
floooh/chips

chips emulates 8-bit processors through a single uint64_t pin mask

8-bit chip and system emulators in standalone C headers

1,292 stars95 forksCZlib

At a glance

What is it?
chips is a Zlib licensed toolbox of 8-bit chip emulators, helper code and complete embeddable system emulators written as dependency free C headers in a C99 subset. Its defining mechanism is a pin bit mask, where a tick function takes the chip's input and output pins as a uint64_t, computes one tick and returns a possibly modified mask.
Who is it for?
chips fits a developer who wants to embed an 8-bit processor emulator in a C or C++ project without a dependency tree, since every emulator is a header you drop in, and it fits anyone building an emulator-based IDE, a hardware teaching tool or a retro machine that has to be reproducible across gcc, clang and MSVC.
Can I use it commercially?
Yes. Zlib is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 27 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 21, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Every emulator is one header you include

chips describes itself as a toolbox of 8-bit chip emulators, helper code and complete embeddable system emulators in dependency-free C headers, and the qualifier about the C dialect matters more than it first appears. The code is a subset of C99 that compiles on gcc, clang and cl.exe.

That single sentence tells you what the project is optimising for. A dependency-free header means there is nothing to install, nothing to version, nothing to resolve. You copy the header you want into your tree, or you include it, and it compiles. For a project whose entire purpose is to let you embed an emulated processor inside another program, that is the property that matters most, because every alternative in this space tends to arrive as a package with a build step, a platform matrix and a set of transitive dependencies.

The primary language is C, and the licence is Zlib, which is a permissive licence with a short notice requirement and no copyleft. The repository layout is organised by role rather than by language, with a chips/ directory for the individual emulators, systems/ for the complete machines, util/ for helper code, ui/ for interface pieces, and codegen/ for whatever is generated rather than hand written. The presence of a codegen/ directory alongside a CHANGELOG.md suggests a workflow where parts of the headers are produced by a script rather than typed out, which is a reasonable way to keep a large set of repetitive chip definitions consistent.

There is also a fips.yml file at the root, and a separate repository for schematics, manuals and research material at github.com/floooh/emu-info, which tells you the project is maintained alongside a documentation effort about the actual hardware.

The repository holds no releases. The last push to master was on 2026-09-26, and the CHANGELOG.md is the only version history in the tree.

The pin bit mask is the whole interface

The stated USP of the chip emulators is how they communicate with the outside world, and the mechanism is worth understanding precisely, because it determines what you can and cannot do with the emulators.

A pin bit mask is used. A tick function takes a uint64_t as input where the bits represent the chip's in and out pins. The tick function inspects the pin bits, computes one tick, and returns a potentially modified pin bit mask.

So the core of a chip emulator's external interface is a single 64-bit integer in and a single 64-bit integer out, plus a small number of callbacks on some chips. There is no callback for every pin, no separate input and output ports, no register accessor API. The state lives inside the emulator struct, and the pins are expressed as bits in the mask.

The consequences run in both directions. On the positive side, the interface is trivially portable, it is the same in C, in C++ and in a WebAssembly build, and wiring a system together is described as more or less just wiring those chip emulators together just like on a breadboard. There is no abstraction layer between the chips, so a machine assembled from emulated chips behaves the way a real board behaves, including the wiring mistakes that a higher level emulator would hide.

On the negative side, 64 pins is 64 pins. A chip with more external signals than that does not fit the scheme without splitting, and a chip with fewer wastes bits. And the mask is untyped, so nothing at compile time tells you whether bit 17 is an input, an output, a clock or a chip select. The pin assignment has to be documented somewhere, and the README does not include that table, so it lives in the headers themselves.

One thing the mask does not model is the passage of time. A tick is one call, and the caller decides what a tick means in wall clock terms. That makes the emulator deterministic and as fast or as slow as the host allows, but it also means the caller has to understand the chip's clocking to advance it correctly.

The system emulators take shortcuts the chip emulators do not

The README is candid about where the emulation departs from reality, and the shape of the compromise is worth reading before you trust a result.

In reality, most emulators are not quite as pure, as this would affect performance too much or complicate the emulation. The stated reasons are performance and complexity, and the two categories of shortcut are named.

Some chip emulators have a small number of callback functions, which is a partial retreat from the pure mask interface. Where a chip needs a side effect that cannot be expressed as a pin, for example a chip that talks to a display or a sound device, a callback is the escape hatch, and the number of them is kept small on purpose.

The address decoding in the system emulators often takes shortcuts instead of simulating the actual address decoding chips. This is the significant one. A real machine of this era had address decoding built from glue logic, and a strict emulator would emulate that logic, including its delays and its quirks. The system emulators do not, they compute the address decode directly in software.

There is exactly one exception named, the lc80 emulator, which does simulate the real decoding chips. So the default is a shortcut and one specific machine is the faithful case, and which one you are using determines how much you can trust cycle level behaviour.

That distinction matters for what you can conclude from an emulation. If you are writing a game, a demo, or a piece of software that runs on the emulated machine and you want to know whether it would work on real hardware, the shortcuts are usually harmless. If you are studying the hardware itself, the timing of memory access, or the interaction between two chips that share a bus, then the address decode shortcut is exactly the part you were interested in, and the lc80 is the case to look at.

Tests and examples live in a separate repository

The testing arrangement is stated in one line at the top of the README, and it is an unusual one.

Tests and example code is in a separate repo: https://github.com/floooh/chips-test.

So the headers are in this repository and everything that exercises them lives elsewhere. That has a defensible rationale for a header-only project, since the test code is not part of the deliverable and does not need to ship, and it keeps the chips/ tree clean of a large amount of test scaffolding. The downside is that the test suite is one repository away, so cloning chips alone gives you no way to check that a change broke something.

The example emulators compiled to WebAssembly are published at https://floooh.github.io/tiny8bit/, which is a clever way to demonstrate a C project that has no build tooling requirements. If the headers compile to WebAssembly and run in a browser, the dependency-free claim is proven in the strongest way, because a browser is about as constrained an environment as an embedder gets.

The build status badge points at a GitHub Actions workflow named build_and_test, so the CI does run builds and tests on the headers even though the test code lives in another repository, most likely by pulling it in as a checkout step.

For someone evaluating the project, the useful next step is to look at the tests rather than the headers. A header-only emulator library with a separate test repository is either very well tested or not tested at all, and the answer is visible in the other repository rather than in this one.

Where chips is the wrong tool

The first wrong case is cycle accurate hardware research. The address decoding shortcuts are the blocker, and the single exception of the lc80 suggests the project is not aiming at that goal. If your question is about the exact timing of a real machine, you want an emulator that models the decoding logic, and the way to get that here is to use the one faithful machine rather than to expect the framework to give it to you.

The second wrong case is a chip outside the 8-bit range. Everything here is 8-bit, which covers the classic home computer and console processors, and it does not cover anything wider. A 16-bit or 32-bit part is a different project.

The third wrong case is a project that needs a maintained package with a semantic version. There are no GitHub releases, the header library has no version pinning mechanism beyond the commit you check out, and the CHANGELOG.md is the only record of what changed. For a component that gets vendored into a larger codebase, that means you own the update, and you own the audit of a header that implements a processor's behaviour.

The fourth wrong case is a need for a simulator with a debugger, a disassembler, a file system and a UI. Those exist, and they are not here. The ui/ directory suggests some interface code is included, and the WebAssembly examples show the emulators can be driven, but a full machine simulator is a different category of software from a set of chip headers, and expecting one library to be both is a category error.

How it differs from a full machine emulator

The comparison worth making is with the emulators people usually reach for, and the difference in approach is visible in the repository structure.

A full machine emulator is a program. It has a main loop, a display, a keyboard handler, a sound device, a file system, maybe a debugger, and it runs as an application. Everything about it is built around the idea that the user wants to interact with a machine.

chips is a set of components. The chips/ directory holds the emulated processors and peripherals, the systems/ directory holds assembled machines built out of them, and the wiring between the two is the pin mask. There is no user interface in the core, and the ui/ directory is separate. The example emulators compiled to WebAssembly exist to demonstrate the components, not to be the product.

That is the right shape for the embedder. A university teaching tool, an emulator based IDE for a homebrew computer, or a game that lets the player program an emulated machine all want the machine as a library, and they want to draw the screen themselves in whatever framework they have. A full machine emulator gives them a fixed display and a fixed input model, and extracting the machine from it is work.

The second difference is the fidelity gradient. A full machine emulator usually has one fidelity level, it emulates the machine as accurately as the author could manage. chips has a gradient, from the pure pin mask chip emulators at one end, through the chip emulators with a few callbacks, to the system emulators with the address decode shortcut, and one machine at the accurate end. That gradient is a design choice, and it means you can pick the fidelity you need for a given use instead of paying for accuracy you do not need.

The third difference is the build cost. A full machine emulator is a project with a build system and a dependency tree. chips is headers that compile with gcc, clang and MSVC, which is what makes it embeddable in a codebase that already has its own conventions.

Editorial conclusion

chips fits a developer who wants to embed an 8-bit processor emulator in a C or C++ project without a dependency tree, since every emulator is a header you drop in, and it fits anyone building an emulator-based IDE, a hardware teaching tool or a retro machine that has to be reproducible across gcc, clang and MSVC. It does not fit a project that needs cycle accurate emulation of a specific chip, since the README is explicit that the address decoding in the system emulators takes shortcuts rather than simulating the actual decoding chips. Before adopting it, check the CHANGELOG.md for the current state of the headers you need, verify the chip you want is present in chips/ and the machine in systems/, and note that the repository has no GitHub releases and the last push was on 2026-09-26.

Frequently asked questions

What is the chips library and what language is it written in?

chips is a toolbox of 8-bit chip emulators, helper code and complete embeddable system emulators written in dependency-free C headers, using a subset of C99 that compiles on gcc, clang and cl.exe. The licence is Zlib.

How do chips emulators communicate with the outside world?

Through a pin bit mask. A tick function takes a uint64_t whose bits represent the chip's in and out pins, inspects the pin bits, computes one tick, and returns a potentially modified pin bit mask. A complete emulated computer is then built by wiring those chip emulators together.

Are the chips emulators cycle accurate?

Not always. The README says that in reality most emulators are not quite as pure, because this would affect performance too much or complicate the emulation. Some chip emulators have a small number of callback functions, and the address decoding in the system emulators often takes shortcuts instead of simulating the actual address decoding chips, with the lc80 emulator named as the exception.

Where are the tests and example code for chips?

In a separate repository at github.com/floooh/chips-test, while this repository holds the headers themselves. Example emulators compiled to WebAssembly are published at https://floooh.github.io/tiny8bit/, and a build and test workflow runs in GitHub Actions.

Where can I find schematics and manuals for the emulated hardware?

The README points to a separate research repository at github.com/floooh/emu-info for schematics, manuals and research material. The repository itself also has a CHANGELOG.md, a chips/ directory for the emulators, a systems/ directory for complete machines, and util/, ui/ and codegen/ directories.

Official sources

  1. floooh/chips on GitHub
  2. Issues
  3. License: Zlib
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/floooh-chips.svg)](https://hysenlabs.com/projects/floooh-chips)

Was this useful?