{"id":22122727,"url":"https://github.com/timendus/chipception","last_synced_at":"2026-01-04T19:48:03.850Z","repository":{"id":204270506,"uuid":"611195235","full_name":"Timendus/chipception","owner":"Timendus","description":"A CHIP-8 and SUPER-CHIP interpreter written in XO-CHIP. Because CHIP-8 interpreters have been written in every programming language and the platform also deserves one written in CHIP-8 itself! 😄","archived":false,"fork":false,"pushed_at":"2024-06-25T20:36:18.000Z","size":7174,"stargazers_count":12,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-29T12:47:52.539Z","etag":null,"topics":["8-bit","8-bit-computer","chip-8","chip-8-emulator","chip-8-interpreter","emulation","retrocomputing","super-chip","xo-chip"],"latest_commit_sha":null,"homepage":"https://timendus.github.io/chipception/","language":"Roff","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Timendus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2023-03-08T10:16:26.000Z","updated_at":"2025-01-11T03:22:15.000Z","dependencies_parsed_at":null,"dependency_job_id":"34a191a9-5906-4f72-ad61-f6eb7ba23c7c","html_url":"https://github.com/Timendus/chipception","commit_stats":null,"previous_names":["timendus/chipception"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Timendus%2Fchipception","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Timendus%2Fchipception/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Timendus%2Fchipception/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Timendus%2Fchipception/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Timendus","download_url":"https://codeload.github.com/Timendus/chipception/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245226335,"owners_count":20580701,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["8-bit","8-bit-computer","chip-8","chip-8-emulator","chip-8-interpreter","emulation","retrocomputing","super-chip","xo-chip"],"created_at":"2024-12-01T15:27:30.545Z","updated_at":"2026-01-04T19:48:03.813Z","avatar_url":"https://github.com/Timendus.png","language":"Roff","funding_links":["https://ko-fi.com/T6T0DOOWP"],"categories":[],"sub_categories":[],"readme":"[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/T6T0DOOWP)\n\n# Chipception\n\n![Chipception title screen](./pictures/title-top.png)\n\nA CHIP-8 and SUPER-CHIP interpreter written in XO-CHIP. My submission to\n[Octojam 10](https://itch.io/jam/octojam-10). Because CHIP-8 interpreters have\nbeen written in *every* programming language and the platform also deserves one\nwritten in CHIP-8 itself! 😄\n\n* [This program on Itch.io](https://timendus.itch.io/chipception-os)\n* [Run Chipception in your browser](https://timendus.github.io/chipception/)\n* [Download the ROM](https://github.com/Timendus/chipception/raw/main/dist/chipception.ch8)\n* Chipception was featured on the\n  [OctoJam 10 Showcase](https://www.youtube.com/watch?v=u1f9J6odZBs\u0026list=PLvsRQ9bQ1QDNnDaMyLjhue2ULbDK5Dil0\u0026t=3537s) (YouTube)\n\n## How to use Chipception\n\nChipception will provide you with a menu (known as the launcher app) from which\nyou can select ROMs to run. You can run at most six ROMs in parallel. Note that\nthe launcher app itself counts as a ROM.\n\nThe launcher app will properly start ROMs in either CHIP-8 or SUPER-CHIP mode,\nand with the correct quirks. You can not change those settings interactively.\n\n![Using the launcher app](./pictures/launcher.gif)\n\nThese are the keys that control the launcher:\n\n| CHIP-8 key | Qwerty key     | Function                               |\n| ---------- | -------------- | -------------------------------------- |\n| `5`        | `W` or ↑       | Go up one ROM in the launcher app      |\n| `8`        | `S` or ↓       | Go down one ROM in the launcher app    |\n| `6`        | `E` or `space` | Start selected ROM in the launcher app |\n\nThe CHIP-8 key `A` (or `Z` on a querty keyboard) acts as a global modifier key,\n like a `ctrl` or `alt` key on a computer. It can be used from anywhere to send\nthese commands to Chipception:\n\n| CHIP-8 keys | Qwerty keys | Function                               |\n| ----------- | ----------- | -------------------------------------- |\n| `A` + `1`   | `Z` + `1`   | Cycle through windows (\"Alt-Tab\")      |\n| `A` + `B`   | `Z` + `C`   | \u003cins\u003eC\u003c/ins\u003elose focussed interpreter  |\n| `A` + `D`   | `Z` + `R`   | \u003cins\u003eR\u003c/ins\u003eeset focussed interpreter  |\n| `A` + `5`   | `Z` + `W`   | Move focussed \u003cins\u003ew\u003c/ins\u003eindow around |\n| `A` + `E`   | `Z` + `F`   | \u003cins\u003eF\u003c/ins\u003eullscreen the window       |\n| `A` + `8`   | `Z` + `S`   | \u003cins\u003eS\u003c/ins\u003etart the launcher app      |\n\nWhen you are moving a window, these are the relevant keys:\n\n| CHIP-8 key | Qwerty key | Function                    |\n| ---------- | -----------| --------------------------- |\n| `5`        | `W` or ↑   | Move window up              |\n| `8`        | `S` or ↓   | Move window down            |\n| `7`        | `A` or ←   | Move window left            |\n| `9`        | `D` or →   | Move window right           |\n| `A`        | `Z`        | Return to normal execution  |\n\n## The concept\n\n![Yo dawg, heard you like CHIP-8. So I put CHIP-8 in ur CHIP-8](./pictures/meme.jpg)\n\nChipception is a lot of things. It's primarily just a dumb idea and a bit of a\njoke to write a CHIP-8 interpreter in CHIP-8. But it's also an experiment to\nstart figuring out what an \"operating system\" for CHIP-8 could look like.\n\nCan we do multitasking? Can we have inter-process communication? How do we do\nwindow management? How do you control the \"OS\" with only a 16-key keypad? What\nkind of paradigms from PCs, mobile phones or PDAs make sense for CHIP-8?\n\nI'm not sure if I'm done with this experiment yet, but right now it's just a\ncool talking piece for Octojam 10. And, with it running at 200.000+ instructions\nper frame, yet another ROM to stress-test people's interpreters 😄\n\n## See also\n\nIf you like this, you may also enjoy my other CHIP-8 projects:\n\n  * [3D Viper Maze](https://github.com/Timendus/3d-viper-maze) (XO-CHIP, Octojam\n    7) and [3D VIP'r Maze](https://github.com/Timendus/3d-vipr-maze) (original\n    CHIP-8)\n  * [Alien Inv8sion](https://github.com/Timendus/alien-inv8sion) (XO-CHIP with\n    \"secret 16-colour mode\", Octojam 8)\n  * [Bad Apple!!](https://github.com/Timendus/chip-8-bad-apple) (XO-CHIP,\n    Octojam 9)\n\nIf you are a CHIP-8 emulator / interpreter developer, you may be interested in\nthese projects:\n\n  * [CHIP-8 test suite](https://github.com/Timendus/chip8-test-suite) -\n    A test suite to find all kinds of issues in your interpreter\n  * [CHIP-8 Binary Format](https://github.com/Timendus/chip8-binary-format) -\n    An effort to standardise on a file format for CHIP-8 and friends\n  * [CHIP-8 database](https://github.com/chip-8/chip-8-database) - A repository\n    with metadata for CHIP-8 ROMs\n\n# Development log\n\n## Wait but why..?\n\nI've been thinking about writing a CHIP-8 interpreter in CHIP-8 for almost two\nyears or so. It's just such an insane idea that I can't help but find myself\nattracted to it.\n\nTo be clear: there is absolutely no benefit to just having a CHIP-8 interpreter\nwritten in CHIP-8. It would only allow you to run the exact same programs, but\nslower and probably with more unexpected bugs. Also, it's quite the engineering\nchallenge to make it actually work. So it's a significant investment of time\nthat brings absolutely no tangible benefit. Sounds like my kind of project! 🎉\n\nHowever, thinking about this a bit longer, there are a few cool things we could\ndo with such an interpreter. One is adaptation: it could act as a mediator\nbetween programs and interpreters that don't play nice otherwise, without\nmodifying the original program **or** the interpreter running it. A CHIP-8\nprogram that relies on a version of CHIP-8 (or one with specific quirks) that\nyou don't support in your interpreter could be wrapped in a CHIP-8 CHIP-8\ninterpreter, and run just fine in your interpreter.\n\nAnother kinda cool thing that I wanted to experiment with is multithreaded\nCHIP-8. A CHIP-8 interpreter written in CHIP-8 could theoretically run multiple\nCHIP-8 programs in parallel on a single host interpreter. This has no real\nbenefit, but it would be something cool to play with. It also touches on\nanother itch that I have had for a while and that kinda needed scratching:\nwriting an operating system for CHIP-8.\n\nLast Octojam sysl made [a program that was a mock-up of a CHIP-8 PDA operating\nsystem](https://sysl.itch.io/bim-logo-animation), that they called BIM. It makes\nsense for them to model a \"CHIP-8 OS\" on a PDA-type device, since you can't\nreally \"download\" or \"install\" new programs into a running CHIP-8 interpreter.\nPDAs used to come with a fixed set of \"applications\" like a calendar or a\ncalculator that were just baked into the ROM of the device, each just running\ndirectly on the hardware and taking over full control of the CPU.\n\nHowever, when I dream about a \"CHIP-8 OS\", I think about something that\nresembles the early Unixes, that can run programs in \"user mode\", with a\n\"kernel\" that can do \"scheduling\" or kill misbehaving programs and maybe some\nway for programs to communicate with each other.\n\nSo maybe, just maybe, starting with a CHIP-8 interpreter in CHIP-8 is the first\nstep on the journey towards a true CHIP-8 operating system. One that runs CHIP-8\nprograms, that you can switch between or run in parallel. Maybe a few custom\nopcodes could allow for the program to communicate with the host OS or other\nprograms?\n\nSo I drew this image of a four colour XO-CHIP program running a \"desktop\" GUI\nwith two CHIP-8 programs running in parallel to inspire myself:\n\n![A mocked-up \"CHIP-8 OS desktop running two CHIP-8 programs in\nparallel\"](./pictures/concept1-large.png)\n\nAlright, enough rationalizing an irrational project and having crazy pipe dreams\nabout its potential, let's get to coding 😉\n\n## Getting started\n\nI came up with the project name \"Chipception\", short for \"CHIP-8 Inception\",\nand got to work.\n\n### So what are we up against?\n\nWriting a CHIP-8 interpreter isn't too hard. This will be the fourth time I\nwrite one. But writing one in a language that **is also** the target language\nbrings both a couple of challenges and a couple of shortcuts.\n\nThe good news is that many opcodes can just be passed on to the host interpreter\nas-is. To AND two registers, we just ask the host to AND two registers. Save the\nresult, save the flag register, and we're done (if we're just ignoring quirks).\n\nThe bad news is that we will actually need all the registers that CHIP-8\nprovides us with for running the interpreter. So every opcode will need to\noperate on virtual registers in memory, adding quite a lot of overhead.\n\nNext to that, it's super hard to predict how a CHIP-8 program will use RAM. So\nwe can't gracefully \"share\" the 4K of memory space, without a crazy amount of\noverhead. Our interpreter would have to keep track of which parts of RAM are\nbeing written to and do some kind of memory management. But even then: many of\nthe worth while ROMs for CHIP-8 are 80+ percent of the available storage. In\nthose cases there's just not enough space to add the interpreter at all.\n\nAlso; there's this little thing called self-modifying code, where a CHIP-8\nprogram modifies itself to achieve some goal. For some programs, this trick\n_may_ depend on the fact that a reset of the program loads in a fresh new\nversion of the ROM. So this means that to do it right and be a proper\ninterpreter, we have to make a copy of the ROM before we start execution.\n\nBecause of these memory requirements and the CPU overhead I very soon had to\naccept the fact that this was going to be an XO-CHIP project. And that it will\nonly interpret systems that require less memory than XO-CHIP, like CHIP-8 and\nSUPER-CHIP.\n\n### Getting things going!\n\nThe first version of this program came together in a little over one evening:\ninitialize virtual registers, fetch an opcode, branch correctly on the opcode,\nproxy all the CHIP-8 instructions to operate on the virtual registers. I also\nadded in a few quirks for good measure and my CHIP-8 CHIP-8 interpreter was\nrunning and passing most of the available tests.\n\nThe [quirks test](https://github.com/Timendus/chip8-test-suite#quirks-test) was\nthe hardest to get right, because I was targeting CHIP-8 and SUPERCHIP, but my\nhost system was using XO-CHIP quirks. So my Chipception interpreter needed to\nimplement versions of the required quirks, using the XO-CHIP quirks. Especially\ngetting the `sprite` opcode to clip properly on the edges of the screen was a\nbit of a pain. It also required quite a few cycles per frame.\n\n![Passing the quirks test](./pictures/passing-quirks.png)\n\nSo after doing quite a lot of work on this project, I arrived at this rather\nunsatisfying point. I could successfully run a single CHIP-8 or SUPERCHIP\nprogram in an XO-CHIP interpreter. Just a little bit slower. And precisely no\none could actually see the difference with **not** having done all of this extra\nwork.\n\n## One is none\n\nSo to get some return on investment, I decided that I would immediately take\nthis project in the direction of running multiple interpreters in parallel. If\nyou can run multiple programs next to each other, surely that's obviously\nsomething new. Something different.\n\nBecause all my code was already operating on virtual registers in memory, it\nwas actually not that hard to get it to run multiple virtual CPUs in parallel.\nMaking use of the fact that SUPER-CHIP `hires` is twice the CHIP-8 `lores`\nresolution, I could pretty quickly get Chipception to render this:\n\n![Running multiple interpreters in split-screen](./pictures/split-screen.gif)\n\nWhich is clearly much more cool! A single unmodified CHIP-8 interpreter that's\nrunning four distinct ROMs at once? Now we're talking! 😄\n\nHowever, these programs are chosen quite carefully. If any program tries to\nclear the screen or shift it, everything totally breaks. Also, when you press a\nbutton, all programs register the same keypress. Which is probably not very\nuseful behaviour.\n\nVirtualising the display turned out to be a lot more work than doing the CPU. I\nhad to -- once again -- write a custom double buffered rendering system with a\ncustom sprite drawing routine in CHIP-8 that could draw 8xN and 16x16 sprites as\nwell as get all the quirks right. Then I had to implement the other opcodes to\noperate on those buffers. Just so that each interpreter could have its own\nisolated display behaviour\u003csup\u003e1\u003c/sup\u003e.\n\nAnd then I needed to composit those discrete display buffers together to form\nthe full display output. Because I wanted to be able to move virtual windows\nover each other, those windows also needed to occlude each other. The normal\n`sprite` behaviour does not support that kind of rendering. So the composite\nstep also renders everything to **yet another** virtual display buffer, that is\nthen finally drawn to the screen.\n\nAfter all of that, I decided it was time for some lighter work: I wanted to\nrender some colourful borders around the virtual windows, to make it look a\nlittle bit more like my inspirational drawing. How hard can it really be to\nrender a few lines and squares to a virtual display buffer in an unusual memory\nlay-out?\n\nYeah. So that took me way longer than I care to admit. I put the project down\nfor a couple of days, just because I was too annoyed I couldn't get the damn\nroutine to draw a bloody horizontal line 😂 But after taking a few breaths and\na couple of days off, I managed to produce some primitive drawing routines and\nnow all of a sudden Chipception could do this:\n\n![Running multiple interpreters in windows with borders](./pictures/bordered-windows.gif)\n\nThis is still just a single CHIP-8 ROM running in Octo, with a custom colour\nscheme. This is starting to go somewhere!\n\n_Note 1: I never properly finished the buffer scrolling opcodes as the ROMs I\nchose to run in this interpreter didn't use them. In the end I removed the\nscrolling behaviour entirely to save executable space. So in that sense it's not\na \"full\" SUPER-CHIP interpreter, unfortunately. It can be done, but only at the\nexpense of leaving out some other features._\n\n## Managing windows\n\nNow that I had all these cute little windows into CHIP-8 programs, I felt it was\ntime to make them interactive. I started by introducing the concept of a\n\"focussed window\". The windows were given an ordering so they could behave like\na stack, like people are used to on their regular computers. The window \"on top\"\nis then considered to be \"focussed\". Inspired by my concept art, I made the\nfocussed foreground window blue and the other windows orange.\n\nNow that there is one window that's clearly \"active\", we can do fun things with\nthat. The most important thing: the interpreter in the focussed window gets\nkeypresses, and the others do not. So by switching the focussed window, you also\nchange which program you're interacting with as a user.\n\nSpeaking of switching windows, I implemented a crude \"Alt-Tab\" functionality to\ncycle through the windows on the screen. The CHIP-8 key `A` (mapped to `Z` on a\nQwerty keyboard), being in the bottom left corner of the keypad, became a sort\nof \"function key\" for interacting with Chipception, instead of the currently\nfocussed ROM.\n\nThese are the key combos I wrote to begin with:\n\n| CHIP-8 keys | Qwerty keys | Function                               |\n| ----------- | ----------- | -------------------------------------- |\n| `A` - `1`   | `Z` - `1`   | Cycle through windows (\"Alt-Tab\")      |\n| `A` - `4`   | `Z` - `Q`   | \u003cins\u003eQ\u003c/ins\u003euit focussed interpreter   |\n| `A` - `D`   | `Z` - `R`   | \u003cins\u003eR\u003c/ins\u003eeset focussed interpreter  |\n| `A` - `5`   | `Z` - `W`   | Move focussed \u003cins\u003ew\u003c/ins\u003eindow around |\n\nI later changed `Z` - `Q` to `Z` - `C` because I kept accidentally quiting ROMs\nwhen I tried to cycle through them 🙈\n\nMoving windows around is done with either WASD or the cursor keys on a\ncomputer keyboard, or `5`, `7`, `8` and `9` on a CHIP-8 keypad. Pressing our\nfunction key `A` / `Z` again returns the system into normal mode.\n\nAdmittedly, the combinations make a lot more sense on a Qwerty keyboard than on\na CHIP-8 keypad. See underlined letters. But I wanted to use combinations that I\ncould actually remember 😅\n\nSo now I could switch between CHIP-8 windows, move them around and interact with\nthe CHIP-8 ROMs running in them 🎉\n\n![Managing windows in Chipception](./pictures/window-management.gif)\n\n## Running out of space\n\nUnfortunately, at this point I ran into my arch nemesis. Space constraints.\n\nLast year I battled this foe with [Bad Apple!! in\nXO-CHIP](https://github.com/Timendus/chip-8-bad-apple) and the year before with\n[3D VIP'r Maze](https://github.com/Timendus/3d-vipr-maze) for the original\nCosmac VIP interpreter. For Bad Apple the challenge was fitting the whole music\nvideo, both video frames and sound, into the total XO-CHIP memory size of 64KB.\nWith 3D VIP'r Maze the challenge was fitting the game and its graphics and game\ndata in the lousy 3.2KB of memory that the VIP interpreter allows for ROMs to\nbe.\n\nThis year, truth be told, I really wasn't expecting to run into any significant\nmemory issues. This is an XO-CHIP project. I wasn't doing anything stupid like\ntrying to compress a music video down to an insanely small size. I only have a\nfew ROMs to load, I need some free memory to manage and I have the code for\nChipception itself. If it doesn't fit, I just include fewer ROMs. What could go\nwrong?\n\nWell, after just a couple of days of actual development, I hit the dreaded 3.5KB\nexecutable code limit. It turns out that after four years of this stuff I got\npretty fast at writing lots of CHIP-8 assembly code...\n\n### What's the 3.5KB executable limit?\n\nCHIP-8 ROMs can be as big as you like. You can append bytes to infinity. The\nproblem isn't making the ROM bigger, it's being able to make use of your bytes.\n\nCHIP-8 has something known as the index register. The index register is used to\npoint at memory and then perform operations with the memory being pointed at.\nThe index register is set using a 16-bit opcode that looks like this in\nhexadecimal:\n\n* `0xAnnn`\n\nThe `nnn` here is a placeholder for the address we want the index register to\npoint at. And `nnn` is 12 bits wide. So CHIP-8 can only address 2 to the power\nof 12 bytes, which is 4KB. Subtract from that the fact that CHIP-8 programs\nstart at memory address `512`, and we're left with a maximum adressable ROM size\nof 3.5KB. Anything above that we simply can't point to to make use of it.\n\nThe same applies to the opcodes for jumping and calling subroutines, which look\nlike this respectively:\n\n* `0x1nnn`\n* `0x2nnn`\n\nHere `nnn` is a placeholder for the address we want to jump to or call into. So\njust like with setting the index register, we can't go anywhere that's outside\nthe 3.5KB boundary.\n\n[XO-CHIP](https://github.com/JohnEarnest/Octo/blob/gh-pages/docs/XO-ChipSpecification.md)\nadds a double sized opcode (`0xF000 0xnnnn`) that can set the index register to\na 16-bit value, allowing us to address 2 to the power of 16, which is 64KB.\nMinus the same 512 bytes, but that's not as big of a deal at that scale. But\nXO-CHIP does not give us 16-bit jumps or subroutine calls. Which creates the\ninteresting situation where we can have plenty of space left \"in the ROM\", but\nwe can only use that space for storing data. Not for storing code.\n\nThat's the 3.5KB executable limit.\n\nThe sharp observers among you are now probably screaming two things at your\nscreens:\n\n1. Just move your data to higher addresses, so you can make maximum use of those\n   3.5K for code!\n2. If you can't jump above the 3.5K limit, you can still run code there. How\n   about you just unroll some loops or something and make your code go on\n   forever!\n\nTo the first, I say: I'm already doing just that. One of the main reasons that I\nwrote my [Octopus\npreprocessor](https://github.com/Timendus/chipcode/tree/main/octopus) is that I\nwanted to have an easy way to mark part of my CHIP-8 program as data, and have\nit automatically moved to the end of the ROM. That's working wonders. So yes, I\nhave actually written 3.5KB of executing code.\n\nTo the second: that sounds great, but without jumping we basically lose any\nmeaningful flow control in CHIP-8. Because all the conditional opcodes only jump\nover a single instruction, and in many cases you really need that single\ninstruction to be a jump (over a longer block of code). You could jump over\nsubroutine calls and store the subroutines below the 3.5KB limit, but in\npractice that doesn't buy you much.\n\nIn all honesty, I'm not 100% convinced that CHIP-8 without jumps or subroutines\nis even Turing-complete...\n\nAlso, some XO-CHIP interpreters wrap the program counter around from `0xFFF` to\n`0x000`, or don't support returning from a subroutine to an address that's more\nthan 12 bits. So realisticly, we just have to keep our code below the 3.5KB\nlimit.\n\n### So now what?\n\nTime to optimize. Already. For every feature I add from now on, I will also have\nto cut some dead weight.\n\n## Looks matter\n\nOne thing I remembered was that I already added code to show a background image,\nbut I couldn't get my background image data in memory in the right format. So\nuntil now I was clearing the screen, for which I had also added a separate\nroutine. If I fixed my background data format, I could remove the screen\nclearing code.\n\nSo I manually created the right background image layers in the GIMP to import\ninto my project with the [Chipcode image loader\nplugin](https://github.com/Timendus/chipcode/tree/main/image-loader).\n\n![Background layer one](./pictures/background-layer1.png)\n![Background layer two](./pictures/background-layer2.png)\n\nNext I had to add an 8 by 64 pixels mode to the image loader, which it turns out\nGulrak's excellent [Chiplet assembler](https://github.com/gulrak/chiplet)\nalready supported too. I then also wanted to fix some annoyances with the window\nshadows, so that the windows stick out enough from the background. Just like in\nmy graphical mockup.\n\nAnd voila! I added a feature while also throwing out a routine that I didn't\nneed anymore!\n\n![Windows with background](./pictures/now-with-background.png)\n\nCompare that to the mock-up I made at the start of this project! I was quite\namazed that I had come this far already 😄\n\nAfter some feedback from the #chip-8 channel on the EmuDev Discord I was not\nentirely convinced that these window shadows are the best looking option. Here\nare some alternatives I drew:\n\n![One alternative](./pictures/different-shadows-1.png)\n\n![Another alternative](./pictures/different-shadows-2.png)\n\nAfter messing with the different alternatives in the code a bit, I realised that\nI could implement the last design with the smallest number of instructions.\nChanging the design again saved around 50 bytes 🎉\n\n## Launching programs\n\nIf the idea is for this thing to be a \"CHIP-8 operating system\", then we should\nat the very least be able to launch programs. But I was almost out of executable\nmemory, so writing a start menu or another graphical program launcher was out of\nthe question.\n\nLucky for me, I was already considering having \"Chipception programs\" that could\nachieve some Chipception specific things with custom opcodes. So I quite quickly\nrealised that I didn't really need a whole interface in my executable space, all\nI **really** needed was an opcode for launching a new program. Then I could\nwrite a ROM that would actually be the interactive interface for the user.\n\nOne of the hardest things to figure out was how the launcher ROM could know\nwhich ROMs are available to Chipception. The solution turned out to be quite\nsimple, albeit not super clean.\n\nWhen loading a ROM, Chipception just lazily copies data from the starting\naddress of the ROM all the way until the memory of the virtualized interpreter\nis full. This way I didn't have to store the sizes of the ROM files. That means\nthat any data *after* the launcher ROM is also copied into the launcher's\nmemory, and is, almost accidentally, accessible to the ROM.\n\nSo I just made sure that the memory lay-out of the launcher ROM looks like this:\n\n```python\n: launcher\n    :byte SUPERCHIP\n    :include \"../roms/launcher.ch8\"\n\n\n: rom-table\n    # Number of ROMs, max is currently 32\n    9\n\n    :pointer rom-3d-vipr-maze\n    :include \"../roms/3d-vipr-maze.png\" no-labels\n\n    :pointer rom-cave-explorer\n    :include \"../roms/cave-explorer.png\" no-labels\n\n    :pointer rom-test-suite\n    :include \"../roms/chip8-test-suite.png\" no-labels\n\n    # ...\n```\n\nIt's not pretty, but by having a table with information on the available ROMs\nand their starting addresses loaded right after the launcher ROM, we can show\nthe user which ROMs Chipception has available with a nice graphic, and the\nlauncher ROM can start the selected program by invoking the new\nChipception-specific opcode.\n\n![The launcher ROM in action](./pictures/launcher.gif)\n\nHaving this fancy new launcher meant that my old testing code, that just\nlaunched several interpreters with fixed settings and ROMs, could be slimmed\ndown to a single subroutine. So we once again actually saved executable memory\nspace while adding a new feature!\n\n## Not the first\n\nAround this time I discovered that I wasn't actually the first to write a CHIP-8\ninterpreter in CHIP-8. Which makes perfect sense. If I feel attracted to the\nstupidity of such an idea, surely there are other emulator devs who feel the\nsame. But I had done a Google search before starting the project, and nothing\nshowed up.\n\nBut when sharing some more screenshots of Chipception-in-progress on the EmuDev\nDiscord I was told that [Geotale wrote a CHIP-8 interpreter in\nCHIP-8](https://johnearnest.github.io/Octo/index.html?key=26l2CvY6) in 2021. Mad\nprops to Geotale for daring to take up that project and beating me to it!\n\nLucky for me, their implementation doesn't do multi-tasking and window\nmanagement, nor implement SUPER-CHIP. So my project is still unique in those\nregards, I hope 😉\n\n## Finishing the project\n\nThe last stretch of this project was mostly fixing lingering bugs and adding\nsome polish, constantly fighting against the executable memory limit. I managed\nto squeeze in a title screen with a nifty animation, a full-screen mode and the\nability to run `hires` SUPER-CHIP ROMs.\n\nI have a ton of ideas left, but both running into the executable code limit and\nrunning into the deadline for Octojam told me that I needed to finish this\nproject up for now.\n\nThese ideas were left on the cutting room floor:\n\n  * Allow Chipception to read [CHIP-8 Binary\n    Format](https://github.com/Timendus/chip8-binary-format) files\n  * Add some proper memory management and register how much memory each ROM\n    really needs, so we can run more ROMs in parallel\n  * Have ROMs define their desired window size so not all windows are so similar\n  * Write some more Chipception-specific ROMs that an OS needs, like a process\n    manager, a calculator, Paint, maybe a \"text editor\" 😜\n  * Supporting the XO-CHIP instruction set\n\nAll in all, I'm quite happy with how close I've come to a \"CHIP-8 OS\", in the\nsense of what I described in the beginning of this dev log! 🎉\n\nThanks for reading all of this, and good luck with your own projects! 👋\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimendus%2Fchipception","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftimendus%2Fchipception","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimendus%2Fchipception/lists"}