{"id":51863182,"url":"https://github.com/ncw/gbpi","last_synced_at":"2026-07-24T11:30:24.399Z","repository":{"id":369132691,"uuid":"1262050586","full_name":"ncw/gbpi","owner":"ncw","description":"This calculates the digits of π on a 1989 Nintendo Game Boy, using nothing but its 8-bit Sharp LR35902 CPU and a hand-written spigot algorithm in Z80-ish assembly.","archived":false,"fork":false,"pushed_at":"2026-06-07T14:04:46.000Z","size":40,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-07-11T21:00:07.515Z","etag":null,"topics":["gameboy","pi"],"latest_commit_sha":null,"homepage":"","language":"Assembly","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ncw.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["ncw"],"patreon":"njcw","liberapay":"ncw","custom":["https://rclone.org/donate/"]}},"created_at":"2026-06-07T14:04:25.000Z","updated_at":"2026-06-07T21:51:01.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ncw/gbpi","commit_stats":null,"previous_names":["ncw/gbpi"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ncw/gbpi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncw%2Fgbpi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncw%2Fgbpi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncw%2Fgbpi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncw%2Fgbpi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ncw","download_url":"https://codeload.github.com/ncw/gbpi/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncw%2Fgbpi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35841138,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-24T02:00:07.870Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gameboy","pi"],"created_at":"2026-07-24T11:30:19.953Z","updated_at":"2026-07-24T11:30:24.381Z","avatar_url":"https://github.com/ncw.png","language":"Assembly","funding_links":["https://github.com/sponsors/ncw","https://patreon.com/njcw","https://liberapay.com/ncw","https://rclone.org/donate/"],"categories":[],"sub_categories":[],"readme":"# gbpi - Pi on the Game Boy\n\nThis calculates the digits of π on a 1989 Nintendo Game Boy, using nothing but\nits 8-bit Sharp LR35902 CPU and a hand-written spigot algorithm in Z80-ish\nassembly.\n\n![Screenshot of gbpi calculating Pi](pi.png)\n\n## What it does\n\n`gbpi` computes the decimal digits of π one screenful at a time and prints them\nto the Game Boy's LCD as they are produced. It uses the **Rabinowitz and Wagon\nspigot algorithm**, which emits digits of π from the start onwards using only\ninteger arithmetic on a large array. No floating point is needed, and there is\nno need for high precision arithmetic.\n\nThe CPU has no multiply or divide instructions, so the project includes\nhand-written 16×16→32 bit multiply (`mmul`), 32÷16 bit divide (`mdiv`, `mdiv32`)\nand \"multiply by 10000\" (`mul10k`) routines, each tuned cycle by cycle for\nspeed.\n\nA ~100 Hz timer interrupt counts hundredths of a second so the ROM can report\nhow long the calculation took once it finishes.\n\n## The two versions\n\nThere are two pre-built ROMs in the repository, charting the optimisation work:\n\n| ROM | Algorithm | Speed (1000 digits) |\n| --- | --- | --- |\n| [gbpi-v1-digit-at-a-time.gb](./gbpi-v1-digit-at-a-time.gb) | base 10 - one decimal digit per array element | ~1400 s |\n| [gbpi-v2-4-digits-at-a-time.gb](./gbpi-v2-4-digits-at-a-time.gb) | base 10000 - four decimal digits per array element | **350.43 s** |\n\nSwitching from base 10 to base 10000 packs four decimal digits into every array\nelement, giving roughly a 4× speed-up by processing four digits per pass of the\ninner multiply/divide loop. The current source builds the base-10000 version.\n\nThe number of digits and the working array length are set at the top of\n[`src/main/pi.asm`](src/main/pi.asm):\n\n```asm\nDEF DIGITS = 1000\nDEF LENGTH = 3330\n```\n\n## Running it\n\nThe quickest way to try it is to load one of the pre-built `.gb` files into a\nGame Boy emulator, for example [Emulicious](https://emulicious.net/),\n[SameBoy](https://sameboy.github.io/) or [BGB](https://bgb.bircd.org/):\n\n```sh\nemulicious gbpi-v2-4-digits-at-a-time.gb\n```\n\nThe ROMs should also run on real hardware via a flash cart.\n\n## Building from source\n\nThe project is built with [RGBDS](https://rgbds.gbdev.io/), the Game Boy\nassembler toolchain (`rgbasm`, `rgblink`, `rgbfix`, `rgbgfx`). Install RGBDS,\nthen run:\n\n```sh\nmake            # build dist/gbpi.gb\nmake run        # build and launch in Emulicious\nmake clean      # remove generated files\n```\n\nThe build assembles every `.asm` file under `src/main/`, converts the font PNG\nunder `src/resources/backgrounds/` into Game Boy tile data with `rgbgfx`, links\nthe objects and runs `rgbfix` to patch the ROM header.\n\n## Source layout\n\n| File | Purpose |\n| --- | --- |\n| `src/main/main.asm` | Entry point, interrupt vectors, intro text and the ~100 Hz timer |\n| `src/main/pi.asm` | The π spigot algorithm plus the multiply/divide maths routines |\n| `src/main/display.asm` | LCD control and background clearing |\n| `src/main/text.asm` | Text output, scrolling and the font tile loader |\n| `src/main/memory.asm` | A small memory-copy helper |\n| `src/main/charmap.inc` | Maps ASCII characters to font tile indices |\n| `src/main/hardware.inc` | Game Boy hardware register definitions |\n| `src/resources/backgrounds/bbc-mode1.png` | The font - a BBC Micro MODE 1 typeface, for old times' sake |\n\n## How the algorithm works\n\nThe algorithm comes from the paper:\n\n\u003e Rabinowitz, Stanley; Wagon, Stan (1995). \"A Spigot Algorithm for the Digits\n\u003e of Pi\". *American Mathematical Monthly*. **102** (3): 195–203.\n\u003e [doi:10.2307/2975006](https://doi.org/10.2307/2975006).\n\u003e [JSTOR 2975006](https://www.jstor.org/stable/2975006).\n\n### π as a number in a strange base\n\nThe starting point is this series which can easily be derived from the well known\n[Leibniz formula for π](https://en.wikipedia.org/wiki/Leibniz_formula_for_%CF%80):\n\n```\nπ = 2 + 1/3·(2 + 2/5·(2 + 3/7·(2 + 4/9·(… ))))\n```\n\nRead this as a positional number whose \"digits\" are all `2`, but where each\nposition has a *different* base. In ordinary base 10 the place values are\n1, 1/10, 1/100, … and every position uses the radix 10. Here the place values\nare the nested products of the fractions `i/(2i+1)`, so position `i` effectively\nuses the **mixed radix** `(2i+1)/i`. In that mixed-radix system π is simply\n\n```\nπ = (2 ; 2, 2, 2, 2, …)\n```\n\nThe whole algorithm is therefore a **base conversion**: it takes π written in\nthis `(2i+1)/i` mixed radix and converts it into ordinary base 10 (or, in the\nfast version, base 10000), one block of output digits at a time.\n\n### Converting one block of digits\n\nConverting a number to base *B* is the familiar \"multiply by *B* and take the\noverflow\" trick. To get the next base-10 digit of a fraction you multiply by 10;\nthe integer part that pops out above the point is the next digit, and you keep\nthe fractional remainder and repeat. This program does exactly that, but to the\n*entire mixed-radix number at once*:\n\n1. **Multiply the whole array by the base** (`B = 10`, or `10000` for four\n   digits at a time). Each element of the `digit` array holds the value for one\n   mixed-radix position; all of them are multiplied by `B`.\n2. **Normalise from the low end up**, position by position. At position `i` the\n   value can no longer be ≥ its radix, so it is divided by the denominator\n   `2·i + 1`: the remainder stays in place (it becomes the new digit `2` for the\n   next round, scaled), and the quotient is multiplied by the numerator `i` and\n   **carried** down into position `i-1`. This is just \"carrying\" during base\n   conversion, except each position carries with its own weird radix.\n3. **The carry out of the front** of the array is the integer part produced by\n   multiplying by `B` - i.e. the next base-10 (or base-10000) block of π. It is\n   printed to the screen.\n\nIn the source this is the `.outer` loop in [`src/main/pi.asm`](src/main/pi.asm):\nthe `digit` array is initialised to `2`, `mmul`/`mul10k` do the \"multiply by the\nbase\" step, and `mdiv`/`mdiv32` do the divide-and-carry normalisation that walks\nthe array. The leading carry is assembled in `prev`/`carry` and emitted with\n`printdigit` / `print4digits`.\n\nA subtlety from the paper: the last digit of a block can occasionally need to be\nrevised by a carry from the *next* block (the classic \"`…999999`\" or \"`…000000`\"\nrollover). The code holds the previous block back in `prev` and only commits it\nonce the following block confirms there was no carry, which is the `.prevloop` /\n`.prevok` logic.\n\nFinally, later digits of π need progressively less precision, so the working\narray length is trimmed a little on every pass (about 13 bits ≈ 4 decimal digits\nper pass), shrinking the work as the calculation proceeds - a small extra\nspeed-up beyond the base-10000 change.\n\n## License\n\n[MIT](LICENSE) © Nick Craig-Wood\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fncw%2Fgbpi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fncw%2Fgbpi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fncw%2Fgbpi/lists"}