{"id":16906578,"url":"https://github.com/rsms/rsm","last_synced_at":"2025-06-20T06:06:31.956Z","repository":{"id":45798483,"uuid":"459341066","full_name":"rsms/rsm","owner":"rsms","description":"Virtual computer","archived":false,"fork":false,"pushed_at":"2022-11-17T06:13:34.000Z","size":1615,"stargazers_count":294,"open_issues_count":0,"forks_count":8,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-06-13T05:48:09.854Z","etag":null,"topics":["computer-architecture","emulator","virtual-machine"],"latest_commit_sha":null,"homepage":"https://rsms.me/rsm/","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rsms.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-02-14T22:08:04.000Z","updated_at":"2025-06-01T14:30:18.000Z","dependencies_parsed_at":"2023-01-23T10:32:29.207Z","dependency_job_id":null,"html_url":"https://github.com/rsms/rsm","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/rsms/rsm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsms%2Frsm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsms%2Frsm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsms%2Frsm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsms%2Frsm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rsms","download_url":"https://codeload.github.com/rsms/rsm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsms%2Frsm/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260891142,"owners_count":23077909,"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":["computer-architecture","emulator","virtual-machine"],"created_at":"2024-10-13T18:43:24.000Z","updated_at":"2025-06-20T06:06:26.938Z","avatar_url":"https://github.com/rsms.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg src=\"etc/rsm.svg\" alt=\"RSM\" width=96\u003e\n\nRSM is a virtual computer, a form of virtual machine.\n\n- [simple RISC instruction set](#isa) with plenty of general-purpose registers.\n- [virtual memory](etc/vmem.txt) means programs have no access to host memory addresses and all memory accesses are checked. It also means all RSM programs have the same address space (currently 48 bits; 256 TiB) and could even be migrated across hosts at runtime.\n- embraces the linear memory model -- addressing memory is a simple and easy to-understand way to deal with data. Prefer memory-mapped I/O over custom system calls.\n- [multi-threaded Go-style task scheduler](src/sched.h)\n- portable and embeddable, without dependencies. (RSM can even build without libc.)\n  - entire API in one header: [src/rsm.h](src/rsm.h)\n- simple explicit [assembly language](#assembly-language)\n  - compiles to very compact, self-contained [\"ROM\" files](etc/rom-layout.txt)\n  - RSM comes with an integrated assembler, making it possible to compile \u0026 run code at runtime. (It can be disabled with a macro if desired in embedding scenarios.)\n  - includes an AST API for code generation without an intermediate assembly step, useful if you want to make a compiler that targets RSM.\n\nProject goals:\n1. learn, have fun -- simplicity\n2. substrate, a thing to make other thing on\n3. longevity -- I want to be able to run a (multimedia) program in 10+ years\n\n\"RSM\" initially stands for \"rsms's smol machine\" but can also be interpreted as\n\"Really smol machine\", or \"Raggedy-ass special mumbojumbo\", or\nthe recursive acronym \"RSM smol machine\" (in case you miss the golden days of PHP), or\nanything you'd like it to mean! Your imagination is really the limit here my friend.\n\n\u003e **Status of this project:** This is a passion project and thus is not \"production grade\" stuff. The instruction set and semantics are changing. I'd be thrilled and happy if you play with RSM and build stuff on it, but please do keep in mind that stuff will change. Contributions are welcome after [an initial discussion](https://twitter.com/rsms)\n\nWork in progress, TODO:\n- Finish the scheduler\n- Framebuffer for drawing graphics (maybe even webgpu?)\n- Audio\n- Lots of little small pieces here and there [marked with \"TODO\" in the code](https://github.com/rsms/rsm/search?l=C\u0026o=desc\u0026q=TODO\u0026s=indexed\u0026type=code)\n\n\n## Try it\n\n[Download a binary for your platform](https://github.com/rsms/rsm/releases/latest) and try this:\n\n```shell\n$ cat \u003e hello.rsm \u003c\u003cEND\nfun main(i32) {\n  const STDOUT = 1\n  data message = \"Hello world\\n\"\n  R0 = message // address of string\n  R1 = 12      // length of string\n  R0 = write R0 R1 STDOUT\n}\nEND\n$ rsm hello.rsm\nHello world\n$\n```\n\n\n## Building \u0026 running\n\n```shell\n$ ./build.sh -debug\n$ ./out/debug/rsm -d -R0=15 examples/factorial.rsm\n# R0 will contain the result 1307674368000\n```\n\nYou'll need the following things to build rsm:\n- bash (or a bash-compatible shell like zsh)\n- [ninja](https://ninja-build.org) (or a ninja-compatible program like [samurai](https://github.com/michaelforney/samurai))\n- C11 compiler with libc (e.g. clang or GCC)\n\nYou can use `rsm` as a really awkward calculator:\n\n```sh\n$ echo 'fun x() { R0 = R0 * 2; ret; }' | out/debug/rsm -d -R0=123\n# R0 will contain the result 246\n```\n\nRSM assembly can be compiled into a ROM file which can later be executed:\n\n```sh\n$ echo 'fun x() { R0 = R0 * 2; ret; }' | out/debug/rsm -o multiply.rom\n$ out/debug/rsm -d -R0=123 multiply.rom\n# R0 will contain the result 246\n```\n\n## Example\n\n```sh\n$ cat \u003c\u003cEXAMPLE \u003e example.rsm\nfun factorial(i32) i32 {\n    R1 = R0        // ACC = n (argument 0)\n    R0 = 1         // RES (return value 0)\n    ifz R1 end     // if n==0 goto end\n  b1:              // \u003c- [b0] b1\n    R0 = R1 * R0   // RES = ACC * RES\n    R1 = R1 - 1    // ACC = ACC - 1\n    if R1 b1       // if n!=0 goto b1\n  end:             // \u003c- b0 [b1]\n    ret            // RES is at R0\n}\nEXAMPLE\n$ out/debug/rsm -d -R0=15 example.rsm\n# R0 will contain the result 1307674368000\n```\n\nSee the `examples/` directory for more.\n\n\u003ca name=\"isa\"\u003e\u003c/a\u003e\n## Instruction Set Architecture\n\nInstructions are fixed-size, 32 bits wide, little endian.\nPC and jump- \u0026 branch destinations are expressed in #instructions rather than bytes.\nThere is room for 256 operations and 32+32 (int+fp) registers (8 bit OP, 5 bit reg)\nMost instructions accept reg or immediate (`i` bit is set) as last argument\n\n```\n        ┌───────────────┬─────────┬─────────┬─────────┬─┬───────────────┐\n  bit   │3 3 2 2 2 2 2 2│2 2 2 2 1│1 1 1 1 1│1 1 1 1  │ │               │\n        │1 0 9 8 7 6 5 4│3 2 1 0 9│8 7 6 5 4│3 2 1 0 9│8│7 6 5 4 3 2 1 0│\n        ├───────────────┼─────────┼─────────┼─────────┼─┼───────────────┤\n  ABCD  │         D (8) │  C (5)  │  B (5)  │  A (5)  │i│     OP (8)    │\n        ├───────────────┴─────────┼─────────┼─────────┼─┼───────────────┤\n  ABCw  │                  C (13) │  B (5)  │  A (5)  │i│     OP (8)    │\n        ├─────────────────────────┴─────────┼─────────┼─┼───────────────┤\n  ABw   │                            B (18) │  A (5)  │i│     OP (8)    │\n        ├───────────────────────────────────┴─────────┼─┼───────────────┤\n  Aw    │                                      A (23) │i│     OP (8)    │\n        └─────────────────────────────────────────────┴─┴───────────────┘\n```\n\nRegisters:\n- 30 general-purpose integer registers R0…R29\n- 30 general-purpose floating-point registers F0…F29\n- Context register CTX (R30)\n- Stack pointer SP (R31)\n- Floating-point status FPSR (F31)\n- _TODO: is a fp control reg needed for stuff like 0div traps? No... no._\n\n\n### Calling convention\n\n- first 8 integer argument/return values in R0…R7, rest on stack\n- first 8 F.P. argument/return values in F0…F7, rest on stack\n- anything larger than the register size goes on stack\n- caller saves R0…R18, F0…F18 (owned by callee)\n- callee saves R19…R29, F19…F29 (owned by caller)\n- convention inspired by [AAPCS64](https://github.com/ARM-software/abi-aa)\n\n#### Callee-owned registers\n\nCallee-owned (caller-saved, temporary) registers.\nCaller needs to save these before a call (if caller uses them.)\nCallee can freely use these registers.\n\n    R0…R7   1st…8th integer argument/return value\n    F0…F7   1st…8th floating-point argument/return value\n    R8…R18  General purpose\n    F8…F18  General purpose\n\n#### Caller-owned registers\n\nCaller-owned (callee-saved, long-lived) registers.\nCaller does not need to save these registers.\nCallee using these must save and later restore their values before returning.\n\n    R19…R29   General purpose\n    F19…F29   General purpose\n    SP (R31)  Stack pointer\n\n\n### Special registers\n\n    CTX  (R30)  Context (like AAPCS platform reg and Go's G)\n    SP   (R31)  Stack pointer\n    -    (F30)  Reserved (unused)\n    FPSR (F31)  Floating-point status\n\n\n## Assembly language\n\n### Syntax\n\nWhite-space is ignored\n\n```abnf\nfile       = (fundef | constdef | datadef)*\n\nconstdef   = \"const\" name type? \"=\" expr \";\"\ndatadef    = \"data\" name (type (\"=\" expr)? | \"=\" expr) \";\"\n\nfundef     = \"fun\" name \"(\" params? \")\" result? funbody?\nparams     = param (\",\" param)*\nresult     = param (\",\" param)*\nparam      = name type | type\nfunbody    = \"{\" block0? block* \"}\"\nblock0     = blockstmt*\nblock      = name \":\" blockstmt*\nblockstmt  = operation | assignment | binop | constdef | datadef\n\ntype       = inttype | arraytype\ninttype    = \"i1\" | \"i8\" | \"i16\" | \"i32\" | \"i64\"\narraytype  = type \"[\" intlit \"]\"\n\noperation  = opcode operand*\n           ; brz R1 end\nbinop      = operand (\"-\" | \"+\" | \"*\" | \"/\") operand\n           ; x + 3\nassignment = reg \"=\" (operation | operand) \";\"\noperand    = reg | literal | name\n\nliteral    = intlit\nintlit     = \"-\"? (binlit | declit | hexlit)\nbinlit     = \"0b\" (\"0\" | \"1\")+\ndeclit     = (0-9)+\nhexlit     = \"0x\" (0-9A-Fa-f)+\n\nname       = (\"_\" | A-Za-z | uniprint) (\"_\" | A-Za-z | 0-9 | uniprint)\n\nuniprint   = \u003cutf8 encoding of printable unicode codepoint\u003e\n\nopcode     = copy | copyv\n           | load | load4u | load4s | load2u | load2s | load1u | load1s\n           | store | store4 | store2 | store1\n           | push | pop\n           | add | sub | mul | adds | subs | muls\n           | div | mod\n           | and | or | xor | shl | shrs | shru | binv\n           | not\n           | eq | neq | ltu | lts | lteu | ltes | gtu | gts | gteu | gtes\n           | if | ifz | call | jump | ret\n           | mcopy | mcmp\n           | write | read\n```\n\nComments are ignored and can appear wherever whitespace can appear\n\n```abnf\ncomment      = linecomment | blockcomment\nlinecomment  = \"//\" \u003cany character except LF\u003e \u003cLF\u003e\nblockcomment = \"/*\" \u003cany character\u003e \"*/\"\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frsms%2Frsm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frsms%2Frsm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frsms%2Frsm/lists"}