{"id":13792739,"url":"https://github.com/siraben/zkeme80","last_synced_at":"2025-04-09T16:19:22.932Z","repository":{"id":49946676,"uuid":"162269074","full_name":"siraben/zkeme80","owner":"siraben","description":"An assembler and operating system for the TI-84+ written in Scheme, Forth and Z80 assembly.","archived":false,"fork":false,"pushed_at":"2024-04-21T02:16:06.000Z","size":1346,"stargazers_count":235,"open_issues_count":2,"forks_count":5,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-04-09T16:19:16.471Z","etag":null,"topics":["assembler","assembly","forth","nix","scheme","ti84","z80"],"latest_commit_sha":null,"homepage":"","language":"Scheme","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/siraben.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}},"created_at":"2018-12-18T10:13:01.000Z","updated_at":"2025-02-14T23:07:28.000Z","dependencies_parsed_at":"2024-08-03T22:07:05.489Z","dependency_job_id":"adaec4f9-3439-4fef-af9f-45e21e1c87cc","html_url":"https://github.com/siraben/zkeme80","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/siraben%2Fzkeme80","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/siraben%2Fzkeme80/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/siraben%2Fzkeme80/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/siraben%2Fzkeme80/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/siraben","download_url":"https://codeload.github.com/siraben/zkeme80/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248065281,"owners_count":21041872,"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":["assembler","assembly","forth","nix","scheme","ti84","z80"],"created_at":"2024-08-03T22:01:15.511Z","updated_at":"2025-04-09T16:19:22.915Z","avatar_url":"https://github.com/siraben.png","language":"Scheme","funding_links":[],"categories":["Scheme"],"sub_categories":["course"],"readme":"# zkeme80 - a Forth-based OS for the TI-84+ calculator\n![Build Status](https://github.com/siraben/zkeme80/workflows/Build/badge.svg)\n\n![OS screenshot](screenshot.png)\n![OS animation](demo.gif)\n\n**TLDR:** `assembler.scm` is the assembler, `zkeme80.scm` is the OS.\nTo build the rom, run `make build`.  There are no dependencies apart\nfrom a recent version of Guile, supporting the modules `bytevectors`\nand `srfi-9` records.  Other Scheme implementations have not been\ntested.\n\nAlternatively, if you're using the Nix package manager on macOS or\nLinux, running `nix-build \u0026\u0026 ./result` in the root of this repository\nbuilds the OS and emulator, then runs it.\n\n## Why another OS for the TI-84+?\nThe TI tinkering community has long loathed the proprietary nature of\nthe default TI-OS.  Few projects have attempted to create a viable\nalternative, fewer have matured to a usable state, and none are\ncurrently able to actually let you use the calculator *as a\ncalculator*.\n\nIf you've been looking at operating systems for the TI-84+, chances\nare you've come across **KnightOS**.  It's well developed and has\nplenty of Unix-like features such as filesystems and tasks, and even a\nC compiler.  But maybe that's not what you want.  You want a minimal\noperating system that allows you to extend it in any way you wish,\nbonus points if you don't need to know Z80 assembly to do so.\n\n**zkeme80** is that operating system, a minimal core with a mostly\n[ANS standard](https://forth-standard.org/standard/words) conforming\nForth interpreter/compiler.  From words covering sprites and graphics,\nto text and memory access, everything you need to make the next hit\nSnake clone or RPN-based math layer is already there.  **zkeme80**\nlowers the barrier of entry for customizing an operating system and\nenable rapid development cycles.  Below the Forth layer, you'll find\ntwo lowest level and highest level languages, Z80 assembly and Scheme.\nThe best assembler is an extensible one, where writing macros should\nbe a joy, not a pain, and Scheme has that macro system.\n\nOn my MacBook Pro 11,1 running NixOS it takes around 13.5 seconds\n(real time) to compile the operating system for the first time with\n`make build`, and subsequent builds involving only changes to `.fs`\nfiles take around 0.5 seconds (real time).\n\n## Why Forth?\nOS development is hard, doubly so if you're using assembly.  Keep\ntrack of calling conventions, or which routines preserve which\nregisters is a tedious and error-prone task.  Nested loops and\n`switch` statements are out of the window.  And most importantly, it\nisn't easy to allow the user to extend the operating system.  Forth\nchanges that.  It's just as low level as assembly, but it can be as\nhigh level as you want.  Want exceptions?  They're already there!\nWant garbage collection and memory safety?  Roll your own!  See\n`forth.scm` for more than 200 examples of Forth words.  If you're not\nfamiliar with Forth, I highly recommend *Starting Forth* by Leo\nBrodie.  Get it [here](https://www.forth.com/starting-forth/).\n\n### Notes on standard-compliance\nSome words are not standard.  This is because I copied them from my\nother [Forth/Z80 project](https://github.com/siraben/ti84-forth),\nwhich itself is based on jonesforth.  However, I did consult the ANS\nstandard to incorporate some of their good ideas.  For instance, the\ntest suite currently found in `bootstrap-flash4.fs` is only a very\nslight (sans the floating point stuff) adaptation of the [offical test\nsuite](www.forth200x.org/tests/ttester.fs).  The current version of\nthe operating system runs a series of tests to check the correctness\nof the word environment.  As time goes on I may consider making more\nwords standard-conforming.\n\n### Did you write all of this?\nMost of the assembly code outside of `forth.scm` was taken from\n[SmileyOS](https://www.ticalc.org/archives/files/fileinfo/442/44227.html),\nwhich itself is based on an older version of the [KnightOS\nKernel](https://github.com/knightos/kernel).  I chose SmileyOS because\nit was the most \"minimal\" needed to get nasty stuff such as\nlocking/unlocking flash, display routines, key routines etc. out of\nthe way.  Code here that doesn't exist in SmileyOS was taken from\npublic sources, including the current version of KnightOS.  The rest\nof the operating system is of my own design.\n\n\n## Building and running the operating system\n### Using the Makefile\nRunning `make build` should make generate a file called `zkeme80.rom`\nin the same directory.  Simply pass that file to an emulator such as\n[jsTIfied](https://www.cemetech.net/projects/jstified/) (works in the\nbrowser) and start playing around!\n\nRunning just `make` builds and runs the project, but assumes that you\nhave already properly built `tielm` and can run it with `tielm2` on\nthe shell, and have Guile installed.  Be warned, though, `tilem` is\ntricky to build and you have to enable all sorts of flags and install\ndependencies.  If anyone knows a good emulator for macOS, please let\nme know.\n\n### Using the Nix package manager (macOS or Linux)\nIf you're using the Nix package manager, just clone the repository and\nrun the following to compile and build the assembler, operating\nsystem, and emulator.  It will automatically run the ROM when done.\nProps to `clever` on `#nixos` for figuring out how to build `tilem`.\n\n```shell\n# With flakes\n$ nix run\n# Without flakes\n$ nix-build \u0026\u0026 ./result\n```\n\n## Files included\n- `assembler.scm` assembles s-exp style assembly code into binary.  Simply\n  run `(load \"assembler.scm\")` into your Scheme REPL and\n  run`(assemble-prog sample-prog)` to see the binary data.  Run\n  `(assemble-to-file sample-prog \"out.bin\")` to write a binary file.\n- `zkeme80.scm` is the Forth-based operating system.  Load\n  `zkeme80.scm` then run `(make-rom \"zkeme80.rom\")` to output binary\n  to a file `zkeme80.rom`.\n\n## Design of the assembler\nThe assembler's core uses pattern matching.  The program counter is\nimplemented as a mutable Scheme object `*pc*`.  Labels are kept in a\nglobal alist `*labels*`.  To allow for the use of jumps that refer to\nlabels declared after it, we use multiple passes.  The assembler is\ndesigned to be extensible from various levels; the source code of the\nassembler, pass 1 and pass 2.  Each layer can be extended using the\nfull power of Scheme.\n\nThe extensible nature of the assembler means that users can add\nwhatever features they desire that were not built in already, for\ninstance, re-targeting the assembler or adding missing instructions.\n\n### Structure of assembly programs\nAssembly programs consist of a list of elements that are either\nexpressions or procedures.\n\n### Pass 1\n#### Handling expressions\nEach expression of a program is passed to `assemble-expr` (which also\nchecks if they're well-formed).  `assemble-expr` returns a record\ntype that has the following fields (for a normal instruction):\n\n| Record entry | Type      | Description                                       |\n| :-:          | :-:       | :-:                                               |\n| `length`     | `integer` | The length of the instruction, in bytes.          |\n| `gen-instr`  | `lambda`  | Thunk that computes the actual instruction bytes. |\n\nThe use of converting expressions into record types like this allows\nus to compute the length of the program (and resolve look ahead\nlabels).\n\n#### Handling procedures\nProcedures (Scheme objects that satisfy the predicate `procedure?`)\nthat are embedded in a program must be able to be run without any\narguments, and return either `()` or an instruction record.  This is\nthe main extension mechanism for the assembler.  For instance, in\n`macros.scm` there is a procedure called `fill-until-end` which\ncreates a list of bytes so that the total binary is `#x100000` bytes\nlong.\n\n### Pass 2\nOnce the program makes it through Pass 1, we perform code generation\nand label resolution.  All instruction records are required to have a\n`length` property that tells in advance how many bytes will be\ngenerated from the thunk.  Consistency between this number and what\nthe thunk outputs is checked.  Each instruction record is also checked\nthat it generates only unsigned 8-bit integers.  The result is\nflattened into a list of unsigned numbers, which can be manipulated as\nthe user wishes.\n\n## Debugging\nThe debugging process is pretty simple.  One just has to write a valid\nZ80 assembly program in my s-exp format and run it through a\ndisassembler then compare the output.  If you're feeling particularly\nbrave you may skip this step and try your program out on a Z80 chip.\n\n## Assembler Limitations\nThere is currently no instruction encoding (like the `z80data.tab`\nfile) that the assembler accepts, so to add new instructions the\ncurrent workflow is to look at relevant portions of the Z80 data sheet\nand write new cases in the pattern matcher.  Adding such an encoding\nwould allow the assembler to be retargeted.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsiraben%2Fzkeme80","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsiraben%2Fzkeme80","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsiraben%2Fzkeme80/lists"}