{"id":15062286,"url":"https://github.com/romforth/romforth","last_synced_at":"2025-07-11T05:32:53.713Z","repository":{"id":161048234,"uuid":"551615861","full_name":"romforth/romforth","owner":"romforth","description":"Ultra Portable, Small, Baremetal Forth for various processors","archived":false,"fork":false,"pushed_at":"2024-09-18T16:53:10.000Z","size":2461,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-13T22:22:38.321Z","etag":null,"topics":["arm64","forth","m68k","msp430","pdp11","perl5","risc-v64","sparc","wasm","x86","x86-16","x86-32","x86-64","x86-nasm","z180","z80","z80n","zig"],"latest_commit_sha":null,"homepage":"","language":"Perl","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/romforth.png","metadata":{"files":{"readme":"README","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":"2022-10-14T18:46:20.000Z","updated_at":"2024-10-05T02:56:05.000Z","dependencies_parsed_at":null,"dependency_job_id":"5e791ea5-11c8-471d-a2b4-2a26bfe06fd1","html_url":"https://github.com/romforth/romforth","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/romforth%2Fromforth","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/romforth%2Fromforth/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/romforth%2Fromforth/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/romforth%2Fromforth/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/romforth","download_url":"https://codeload.github.com/romforth/romforth/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225696594,"owners_count":17509766,"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":["arm64","forth","m68k","msp430","pdp11","perl5","risc-v64","sparc","wasm","x86","x86-16","x86-32","x86-64","x86-nasm","z180","z80","z80n","zig"],"created_at":"2024-09-24T23:33:45.892Z","updated_at":"2025-07-11T05:32:53.707Z","avatar_url":"https://github.com/romforth.png","language":"Perl","readme":"romforth is a small, portable, baremetal version of Forth which has been ported\nto various 8/16/32/64-bit microcontrollers with support for both big and little\nendian architectures. So far, it has been ported to the following instruction\nsets: x86 (16-bit, 32-bit and 64-bit), PDP11, 68000, SPARC, Z80, MSP430, ARM64,\nRISC-V(rv32, rv64), WASM, Padauk, 6502.\n\nSo, at a superficial level, romforth is just yet another Forth which has been\nported to a wide variety of CPUs and is meant to be runnable directly from the\nFlash/ROM of the microcontroller.\n\nDig deeper though, and you might see that romforth can also be considered a\n\"porting toolkit\" which enables a \"stepwise porting framework\" that allows you\nto port Forth \"relatively easily\" to any of your favorite CPU architectures.\n\nThe various ports that have been done already can be then be considered as\nproof of concept of this approach to porting Forth.\n\nAt this point you might reasonably ask: Why use Forth for microcontrollers?\nI'll go ahead and claim that Forth is a perfect fit for small, resource\nconstrained systems. Perhaps elsewhere too, but opinions widely differ on that.\nHere's some sample code that might be used to blink an LED every second:\n\n\tloop{\n\t\tgreen led_on\n\t\t500 millisec sleep\n\t\tgreen led_off\n\t\t500 millisec sleep\n\t}loop\n\nromforth is yet another Forth-like implementation meant to (eventually)\nrun on most \"low end\" (ie ROM and RAM constrained) microcontrollers.\n\nSee PORTING for a list of architectures to which romforth has been ported\nas well as all the steps that are required for porting to a new architecture.\n\nUnlike many Forth implementations which require a large number of \"words\" to\nbe implemented before you can do anything with it, romforth is meant to be a\n\"shrink to fit\" implementation where the user decides how much of the Forth\nfunctionality they really need and only implement what they really require.\n\nThere are four \"levels\" of Forth that could be implemented in this way.\nFor lack of better names, I'll refer to these \"levels\" as:\n1/4 : \"oneforth\" (pun intended), which has only primitives and a data stack\n      ROM : ~256 bytes, RAM : in the single digit byte range?\n2/4 : \"twoforth\" which has definitions and a return stack (in addition to\n      the primitives and data stack that \"oneforth\" has)\n      ROM : ~256 bytes, RAM : 16 bytes (or thereabouts in two digit byte range)\n3/4 : \"threeforth\" which has a static dictionary (in addition to the primitives\n      and definitions and the two stacks that \"twoforth\" has)\n      ROM : ~512 bytes, RAM : 16 bytes (or thereabouts in two digit byte range)\n4/4 : a full fledged \"fourforth\"/full/regular Forth with a dynamic dictionary\n      in addition to the rest of the bells and whistles from \"threeforth\".\n      ROM : ~1024 bytes, RAM : 512 bytes or more - to hold the dictionary\n\nThese levels are further broken down into a total of ~73 individual steps which\nimplement incremental pieces of Forth functionality. Each of these steps comes\nwith tests that can be run to verify each additional piece of functionality as\nit is added, one at a time, which helps in having a working implementation at\neach and every step along the way.\n\nBy design, the most compact implementation is limited to use just a little over\n~256 bytes of native code with the rest of the functionality implemented in\nmachine independent code. Currently, ~100 bytes of machine independent Forth\nrelated functionality is used in the x86 implementation. So the overall\nFlash/ROM requirement on x86 is currently about ~350 bytes.\n\nAs mentioned earlier, there is also a regression test suite which is called at\nboot as part of init (which can be optionally #ifdef'ed out) and that currently\ntakes an additional ~500 bytes of machine independent code.\n\nromforth is meant to be extended using new \"purpose built\" Forth words which\ncan be defined in terms of existing Forth words. The new definitions can be\nadded in the machine independent \"defs.4th\".\n\nThe new words that have been defined can then be called directly as part of\nthe CPU boot code/initialization by adding them to \"rom.4th\".\n\nRunning \"make\" will generate a \"forth\" binary which can be flashed into ROM\n(although in all of the implementations that have been completed so far, the\ntesting is done using emulation, not actual hardware). I hope to run this on\nactual hardware real soon now.\n\nThe following (mostly) traditional Forth runtime words are available:\nData Stack operators\t: dup drop nip dip swap over rot 2drop third fourth\nData Stack get/set ops\t: pick stick\nArithmetic\t\t: + - inc(1+) dec(1-) neg\nMemory access\t\t: ! @ c! c@\nComparison operators\t: \u003e \u003c \u003e= \u003c= 0= ~\nI/O\t\t\t: key emit p@ p!\nMemory allocation\t: here alloc\nReturn stack operators\t: \u003er r\u003e\nCall/return\t\t: enter exit call exec\nLoop index\t\t: i\nLiterals\t\t: lit\nBit operators\t\t: \u0026 | ^ \u003c\u003c \u003e\u003e inv\nControl flow\t\t: j(branch) jz(branch0) jnz(branchnz)\nStack switch operators\t: sp@! rp@!\nHalt\t\t\t: bye\nConditionals\t\t: if{ ... }else{ ... }if\nunconditional loop\t: loop{ ... }loop\nwhile loop\t\t: loop{ ... }while{ ... }loop\nuntil loop\t\t: loop{ ... }until{ ... }loop\nfor loop\t\t: for{ ... }for\n\nAt the \"oneforth\" and \"twoforth\" levels of the implementation, compared to\nregular Forth, what is not available is the dictionary. We make up for that by\nproviding an \"umbilical host\"ed solution using a set of scripts, which runs on\nthe host, and will turn the Forth code into byte code which can be run on top\nof the ~350 byte \"runtime\". This \"umbilical host\" provides control flow\nstructures such as conditionals and loop structures which are identical to\nthe ones available at runtime in the dictionary at the \"threeforth\"/\"fourforth\"\nlevels of the implementation.\n\nSo, using about ~350 bytes of \"runtime\", we can write architecture independent\nloops (while, until, for), conditionals (if, else), allocate memory, and even\nrun threads or invoke semi/full-coroutines (if your proclivities tend that way)\n\nIt is reasonable to ask what distinguishes this Forth implementation from\nthe zillion other implementations that already exist. I think the main\ndistinguishing features are that it is portable, small and runs baremetal:\n1. Portable : romforth currently runs on 8/16/32/64 bit architectures as well\n\tas little and big endian CPUs. It was designed with portability in mind\n\tso as to eventually be able to run on \"most\" microcontrollers. The\n\tprimitives implemented in native code are only a few instructions\n\teach. For a compact implementation, only ~256 bytes of native code\n\twill need to be ported to a new architecture.\n2. Small : Designed for low end microcontrollers\n\tOn x86, a minimal init needs ~350 bytes of code and 7 bytes of RAM\n\tAs a proof of concept, for even smaller systems, I've coded up an\n\tx86 bootloader which needs just a dozen bytes of x86 native code\n\tto load the additional bytes in via any available serial interface\n\t- either from an \"umbilical host\" during testing or from, say, an\n\texternal SPI flash part.\n3. Baremetal : Can run directly on the hardware, doesn't require any other\n\tunderlying runtime or OS support.\n\nLicense\n=======\nAll of the code here is licensed under the Affero GPL 3.0 open source license.\nFor exact details about the license please see the LICENSE file. For the\nthinking/intent behind the choice of AGPL, see LICENSE.README\n\nRationale\n=========\nFor a long winded explanation of why this project exists, see RATIONALE\n\nInstallation\n============\nTo make a local copy:\n\tgit clone https://github.com/romforth/romforth\n\nTo build/test, the following dependencies need to be installed:\n(Note 1: the version number in parentheses is the \"known to work\" version used\n\tin testing, older/newer versions may or may not work)\n(Note 2: If you are only doing a partial build for a specific processor by\n\trunning `make` within a subdirectory, a subset of these dependencies is\n\tsufficient. For example, for the x86 port, a C compiler and the `nasm`\n\tx86 assembler might be more than sufficient.)\n\n\t- perl (v5.22.1)\n\t- nasm (version 2.15.05 compiled on Aug 28 2020)\n\t- gcc (version 5.3.1 20160413 (Ubuntu 5.3.1-14ubuntu2))\n\t- binutils ((GNU Binutils) 2.38)\n\t\t- pdp11\n\t\t- m68k\n\t\t- sparc\n\t\t- msp430\n\t\t- aarch64\n\t\t- riscv64\n\t\t- riscv32\n\t- simh (open-simh V4.0-0 Current git commit id: 33aad325)\n\t- zig (0.11.0)\n\t- qemu (7.1.0, via nix)\n\t- sdcc(ucsim) (4.2.0 #13081 (Linux), ucsim: 0.6.4)\n\t- m4 ((GNU M4) 1.4.17)\n\t- msp430-gcc ((GCC) 4.6.3 20120301 (mspgcc LTS 20120406 unpatched))\n\t- mspdebug(from github.com/romforth/mspdebug, until my changes\n\t\tare upstreamed)\n\t- wasmtime (wasmtime-cli 9.0.4)\n\t- perl6 (version 2015.11 built on MoarVM version 2015.11)\n\nAfter installing all the above dependencies, running `make` will build each of\nthe ports and run each of them in an emulator and should complete successfully.\n\nTo do a partial build, you can go into any individual processor specific\ndirectory and run `make` within that subdirectory.\n\nROM/RAM Requirements\n====================\n\nThe table below lists the current ROM usage (in bytes) of the various ports:\n\n.--------------.------------.-----------------.-----------------.\n| CPU          | Primitives | Forth bytecodes | Forth bytecodes |\n|              |            |     (total)     | TESTROM (total) |\n+--------------+------------+-----------------+-----------------+\n| x86          |     264    |   1619 (1883)   |   3047 (3311)   |\n| x86-as       |     264    |   1619 (1883)   |   3047 (3311)   |\n| PDP11        |     276    |   2140 (2416)   |   4272 (4548)   |\n| x86-user     |     445    |   3245 (3690)   |   6548 (6993)   |\n| C/x86        |     445    |   3928 (5848)   |   6985 (7430)   |\n| x86-32       |     385    |   2229 (2614)   |   4288 (4673)   |\n| x86-sys      |     518    |   3245 (3763)   |   6548 (7066)   |\n| m68k         |     378    |   2280 (2658)   |   4348 (4726)   |\n| sparc        |     956    |   2208 (3164)   |   4315 (5271)   |\n| z80          |     491    |   1735 (2231)   |   3178 (3674)   |\n| z80-c        |    1588    |   1563 (3151)   |   2927 (4515)   |\n| z180-sdcc    |    1590    |   1563 (3153)   |   2927 (4517)   |\n| z80n-sdcc    |    1584    |   1563 (3147)   |   2927 (4511)   |\n| msp430-as    |     270    |   2540 (2810)   |   4672 (4942)   |\n| arm-zigcc    |    1272+.. |   3036 (4308)   |   5762 (7034)   |\n| arm64-sys    |    1060    |   3336 (4396)   |   6664 (7724)   |\n| riscv-zigcc  |    1124+.. |   3036 (4160)   |   5762 (6886)   |\n| rv64-sys     |     692    |   3336 (4028)   |   6664 (7356)   |\n| rv32-sys     |     692    |   2302 (2994)   |   4374 (5066)   |\n| msp430-stc   |       0    |   4328 (4328)   |  10060 (10060)  |\n| z80-stc      |       0    |   3456 (3456)   |   7090 (7090)   |\n| msp430-fcode |     344    |   2064 (2408)   |   3308 (3652)   |\n| msp430-f     |     344    |    602 (946)    |   1408 (1752)   |\n| nqh-zig      |    9387    |    341 (9728)   |   1009 (10396)  |\n| wasm32-c     |    1735    |   2840 (4575)   |   5552 (7287)   |\n| pdk14-stc*   |       0    |     15 (125)    |    503 (613)    |\n| pdk14-thr1*  |     264    |     40 (304)    |    609 (873)    |\n| 6502-sdcc    |    2624    |   2060 (4684)   |   3495 (6119)   |\n| 6502-stc     |       0    |    859 (859)    |   3386 (3386)   |\n'--------------'------------'-----------------'-----------------'\n\n*Note: The units for pdk14-stc and pdk14-thr1 are in \"words\" which can be\n       13/14/15/... bits long depending on the processor family.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fromforth%2Fromforth","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fromforth%2Fromforth","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fromforth%2Fromforth/lists"}