{"id":13779480,"url":"https://github.com/rm-hull/byok","last_synced_at":"2025-04-23T16:43:47.030Z","repository":{"id":21467449,"uuid":"24785947","full_name":"rm-hull/byok","owner":"rm-hull","description":"A bare-metal x86 Forth interpreter \u0026 compiler","archived":false,"fork":false,"pushed_at":"2017-08-11T10:48:01.000Z","size":3154,"stargazers_count":56,"open_issues_count":7,"forks_count":11,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-10-03T12:17:29.847Z","etag":null,"topics":["forth","kernel","qemu"],"latest_commit_sha":null,"homepage":"","language":"C","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/rm-hull.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-10-04T09:25:01.000Z","updated_at":"2024-09-02T21:00:24.000Z","dependencies_parsed_at":"2022-08-17T17:20:12.981Z","dependency_job_id":null,"html_url":"https://github.com/rm-hull/byok","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/rm-hull%2Fbyok","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rm-hull%2Fbyok/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rm-hull%2Fbyok/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rm-hull%2Fbyok/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rm-hull","download_url":"https://codeload.github.com/rm-hull/byok/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250472218,"owners_count":21436100,"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":["forth","kernel","qemu"],"created_at":"2024-08-03T18:01:05.668Z","updated_at":"2025-04-23T16:43:46.996Z","avatar_url":"https://github.com/rm-hull.png","language":"C","funding_links":[],"categories":["C"],"sub_categories":[],"readme":"# BYOK - a bare-metal x86 Forth OS\n\nA hobby implementation of a [Forth](https://en.wikipedia.org/wiki/Forth_(programming_language))\ninterpreter and compiler, running directly on top of an x86 machine. The\nscreencast below has been sped up, to offset my slow typing.\n\n![screencast](https://raw.githubusercontent.com/rm-hull/byok/master/doc/screencast-039ece6f.gif)\n\n## Setup / Building\n\nFor development and testing, using [QEMU](http://wiki.qemu.org/Main_Page) is recommended.\nUsing bochs, virtual box or VMware should equally work.\n\nFrom Ubuntu command line (older OS versions may need `qemu-kvm` instead of `qemu-system-i386`):\n\n    $ sudo apt-get install qemu-system-x86 ghex nasm xorriso make grub-pc-bin\n\nBuilding requires a barebones [i686-elf or ARMv7 cross compiler](https://github.com/rm-hull/barebones-toolchain)\ninstalling first. Follow the instructions on that page, and then check it works by running:\n\n    $ i686-elf-gcc --version\n    i686-elf-gcc (GCC) 4.9.1\n    Copyright (C) 2014 Free Software Foundation, Inc.\n    This is free software; see the source for copying conditions.  There is NO\n    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nNext, to completely rebuild the kernel:\n\n    $ make clean\n    $ make build\n\nTo build an ISO image of the kernel:\n\n    $ make iso\n\nThis may then either be burned onto a CD-ROM, or loaded onto a USB stick. Alternatively,\nrunning it in qemu:\n\n    $ make qemu\n\n## Debugging\n\nFrom the ubuntu command line install gdb and [nemiver](https://en.wikipedia.org/wiki/Nemiver):\n\n    $ sudo apt-get install gdb nemiver\n\nBuild an iso image and then launch qemu, making it wait for the debugger\nto attach:\n\n    $ make iso qemu-gdb\n\nIn a separate terminal, launch gdb (or nemiver) and at the GDB prompt,\nconnect to the suspended QEMU and load the symbols from the kernel\nimage:\n\n    $ gdb\n\n    (gdb) target remote localhost:1234\n    Remote debugging using localhost:1234\n    0x0000fff0 in ?? ()\n\n    (gdb) symbol-file kernel/byok.kernel\n    Reading symbols from kernel/byok.kernel...done.\n\nNext, pick a function to break on, and continue/step/inspect as normal:\n\n    (gdb) break repl\n    Breakpoint 1 at 0x101e30: file src/stack_machine/repl.c, line 69.\n\n    (gdb) cont\n    Continuing.\n\n    Breakpoint 1, repl () at src/stack_machine/repl.c:69\n    69\t{\n\n    (gdb) next\n    72\t    history_t *hist = init_history(READLINE_HISTSIZ);\n\n    (gdb) info registers\n    eax            0xffffffff\t-1\n    ecx            0xe\t14\n    edx            0x0\t0\n    ebx            0x400\t1024\n    esp            0x114988\t0x114988\n    ebp            0x0\t0x0\n    esi            0x0\t0\n    edi            0x0\t0\n    eip            0x101e3a\t0x101e3a \u003crepl+10\u003e\n    eflags         0x200206\t[ PF IF ID ]\n    cs             0x8\t8\n    ss             0x10\t16\n    ds             0x10\t16\n    es             0x10\t16\n    fs             0x10\t16\n    gs             0x10\t16\n\n## Implemented Words\n\n\n### forth/src/primitives/arithmetics.c\n\n| Word | Stack Effect | Description |\n|------|--------------|-------------|\n| * | ( x1 x2 -- x3 ) | multiplies x1 with x2, leaves result x3. |\n| */ | ( n1 n2 n3 -- n4 ) | multiplies then divides (n1 x n2) / n3. |\n| */MOD | ( n1 n2 n3 -- n4 n5) | multiplies then divides (n1 x n2) / n3, returning the remainder n n4 and quotient in n5. |\n| + | ( x1 x2 -- x3 ) | adds x1 and x2, leaves result x3. |\n| - | ( x1 x2 -- x3 ) | subtracts x2 from x1, leaves result x3. |\n| / | ( x1 x2 -- x3 ) | divides x1 by x2, leaves result x3. |\n| /MOD | ( n1 n2 -- n-rem n-quot ) | calculates and returns remainder and quotient of division n1/n2. |\n| 1+ | ( x1 -- x2 ) | increments x1 by 1. |\n| 1- | ( x1 -- x2 ) | decrements x1 by 1. |\n| 2* | ( x1 -- x2 ) | multiply x1 by 2. |\n| 2+ | ( x1 -- x2 ) | increments x1 by 2. |\n| 2- | ( x1 -- x2 ) | decrements x1 by 2. |\n| 2/ | ( n1 -- n2 ) | divide n1 by 2. |\n| ABS | ( n -- u ) | return absolute value of n. |\n| MAX | ( n1 n2 -- n3 ) | return the greater of the two signed numbers n1 and n2. |\n| MIN | ( n1 n2 -- n3 ) | return the lesser of the two signed numbers n1 and n2. |\n| MOD | ( n1 n2 -- n3 ) | calculates and returns remainder of division n1/n2. |\n| NEGATE | ( n1 -- n2 ) | change sign of n1. |\n\n### forth/src/primitives/bit_logic.c\n\n| Word | Stack Effect | Description |\n|------|--------------|-------------|\n| AND | ( x1 x2 -- x3 ) | bitwise and x1 with x2, return result x3. |\n| INVERT | ( x1 -- x2 ) | return the bitwise complement of x1. |\n| LSHIFT | ( u1 u2 -- u3 ) | logical shift left u1 by u2 bits. |\n| OR | ( x1 x2 -- x3 ) | bitwise or x1 with x2, return result x3. |\n| RSHIFT | ( u1 u2 -- u3 ) | logical shift right u1 by u2 bits. |\n| XOR | ( x1 x2 -- x3 ) | bitwise exclusive-or x1 with x2, return result x3. |\n\n### forth/src/primitives/comparison.c\n\n| Word | Stack Effect | Description |\n|------|--------------|-------------|\n| 0\u003c | ( n -- f ) | return a true flag if value of n is negative. |\n| 0\u003c\u003e | ( x -- f ) | return a true flag if value of x is not zero. |\n| 0= | ( x -- f ) | return a true flag if value of x is zero. |\n| 0\u003e | ( n -- f ) | return a true flag if value of x is greater than zero. |\n| \u003c | ( n1 n2 -- f ) | compares signed numbers n1 with n2, returns true if n1 is less then n2. |\n| \u003c\u003e | ( x1 x2 -- f ) | compares top two stack elements, returns true flag if different, false otherwise. |\n| = | ( x1 x2 -- f ) | compares top two stack elements, returns true flag if equal, false otherwise. |\n| \u003e | ( n1 n2 -- f ) | compares signed numbers n1 with n2, returns true if n1 is greater then n2. |\n| U\u003c | ( u1 u2 -- f ) | compares unsigned numbers u1 with u2, returns true if n1 is lower then n2. |\n| U\u003e | ( u1 u2 -- f ) | compares unsigned numbers u1 with u2, returns true if n1 is higher then n2. |\n| WITHIN | ( x1 x2 x3 -- f ) | return a true flag if x1 is in the range of x2 ... x3-1. |\n\n### forth/src/primitives/io.c\n\n| Word | Stack Effect | Description |\n|------|--------------|-------------|\n| . | ( n -- ) | convert signed number n to string of digits, and output. |\n| .S | ( -- ) | display stack contents. |\n| CLS | ( -- ) | clear screen. |\n| CURSOR | ( start end -- ) |  |\n| EMIT | ( ascii -- ) | outputs ascii as character. |\n| KEY | ( -- ascii ) | waits for key, returns ascii. |\n| LIST | ( block -- ) |  |\n| LOAD | ( block -- ) |  |\n| PAGE | ( -- ) | clear screen. |\n| SPACES | ( u -- ) | outputs u space characters. |\n| TYPE | ( addr n -- ) | outputs the contents of addr for n bytes. |\n| U. | ( u -- ) | convert unsigned number n to string of digits, and output. |\n\n### forth/src/primitives/memory.c\n\n| Word | Stack Effect | Description |\n|------|--------------|-------------|\n| ! | ( x a-addr -- ) | Store x at a-addr. |\n| ' | ( \\\u003cspaces\u003ename\\\" -- xt )\" | Skip leading space delimiters. Parse name delimited by a space. Find name and return xt, the execution token for name. |\n| (LIT) |  |  |\n| +! | ( x a-addr -- ) | Adds x to the single cell number at a-addr. |\n| , | ( x -- ) | Reserve one cell of data space and store x in the cell. |\n| 0BRANCH | ( x -- ) |  |\n| : | ( C: \\\u003cspaces\u003ename\\\" -- colon-sys )\" | Enter compilation state and start the current definition, producing colon-sys. |\n| ; | ( C: colon-sys -- ) | End the current definition, allow it to be found in the dictionary and enter interpretation state, consuming colon-sys. |\n| \u003eBODY | ( xt -- pfa ) | pfa is the parameter field address corresponding to xt. |\n| \u003eIN | ( -- a-addr ) | a-addr is the address of a cell containing the offset in characters from the start of the input buffer to the start of the parse area. |\n| ?ERROR |  |  |\n| @ | ( a-addr -- x ) | x is the value stored at a-addr. |\n| ALLOT | ( n -- ) | If n is greater than zero, reserve n address units of data space. If n is less than zero, release |n| address units of data space. If n is zero, leave the data-space pointer unchanged. |\n| BRANCH | ( -- ) |  |\n| C! | ( char c-addr -- ) | Store char at c-addr. |\n| C@ | ( c-addr -- x ) | Fetch the character stored at c-addr. |\n| CELLS | ( n1 -- n2 ) | n2 is the size in address units of n1 cells. |\n| CMOVE | ( a1 a2 u --  ) |  |\n| CONSTANT | ( x \\\u003cspaces\u003ename\\\" -- )\" | Skip leading space delimiters. Parse name delimited by a space. Create a definition for name with the execution semantics: `name Execution: ( -- x )`, which places x on the stack. |\n| CREATE | ( \\\u003cspaces\u003ename\\\" -- )\" | Skip leading space delimiters. Parse name delimited by a space. Create a definition for name with the execution semantics: name Execution: ( -- a-addr ) |\n| DISASSEMBLE | ( len a-addr -- ) |  |\n| EXECUTE | ( i*x xt -- j*x ) | Remove xt from the stack and perform the semantics identified by it. Other stack effects are due to the word EXECUTEd. |\n| EXIT | Execution: ( -- ) ( R: nest-sys -- ) | Return control to the calling definition specified by nest-sys. Before executing EXIT within a do-loop, a program shall discard the loop-control parameters by executing UNLOOP. |\n| HERE | ( -- addr ) | addr is the data-space pointer. |\n| IMMEDIATE | ( -- ) | Make the most recent definition an immediate word. |\n| LATEST | ( -- xt ) |  |\n| LITERAL | Compilation: ( x -- ), Runtime: ( -- x ) | Append the run-time semantics to the current definition. |\n| MOVE | ( a1 a2 u --  ) |  |\n| NAME\u003e | ( xt -- len a-addr) | the address and length of the name of the execution token. |\n| PARSE | ( char \\ccc\u003cchar\u003e\\\" -- c-addr u )\" | Parse ccc delimited by the delimiter char. c-addr is the address (within the input buffer) and u is the length of the parsed string. If the parse area was empty, the resulting string has a zero length. |\n| SOURCE | ( -- c-addr u ) | c-addr is the address of, and u is the number of characters in, the input buffer. |\n| THROW | ( i*x -- ) |  |\n| VARIABLE | ( \\\u003cspaces\u003ename\\\" -- )\" | Skip leading space delimiters. Parse name delimited by a space. Create a definition for name with the execution semantics: `name Execution: ( -- a-addr )`. Reserve one cell of data space at an aligned address. |\n| WORD | ( char \\\u003cchars\u003eccc\u003cchar\u003e\\\" -- c-addr )\" | Skip leading delimiters. Parse characters ccc delimited by char.  |\n| WORDS | ( -- ) | List the definition names in alphabetical order. |\n\n### forth/src/primitives/misc.c\n\n| Word | Stack Effect | Description |\n|------|--------------|-------------|\n| DUMP | ( n addr -- ) | Dumps n bytes starting from addr. |\n| LICENSE | ( -- ) | displays the MIT license text. |\n\n### forth/src/primitives/stack_manip.c\n\n| Word | Stack Effect | Description |\n|------|--------------|-------------|\n| -ROT | ( x1 x2 x3 -- x3 x1 x2 ) | rotate the top three stack entries. |\n| 2DROP | ( x1 x2 -- ) | drop cell pair x1 x2 from the stack. |\n| 2DUP | ( x1 x2 -- x1 x2 x1 x2 ) | duplicate cell pair x1 x2. |\n| 2OVER | ( x1 x2 x3 x4-- x1 x2 x3 x4 x1 x2) | copy cell pai x1 x2 to the top of the stack. |\n| 2SWAP | ( x1 x2 x3 x4 -- x3 x4 x2 x1) | exchange the top two cell pairs. |\n| \u003eR | ( x -- )  ( R:  -- x) | move x to the return stack. |\n| ?DUP | ( x -- 0 \\| x x ) | duplicate top stack element if it is non-zero. |\n| DEPTH | ( -- n ) | the number of single-cell values contained in the data stack before n was placed on the stack. |\n| DROP | ( x -- ) | drop top stack element. |\n| DUP | ( x -- x x ) | duplicate top stack element. |\n| NIP | ( x1 x2 -- x2 ) | remove NOS. |\n| OVER | ( x1 x2 -- x1 x2 x1) | copy NOS (next of stack) to top of stack. |\n| PICK | ( xu ... x1 x0 u -- xu ... x1 x0 xu ) | remove u. Copy the xu to the top of the stack. |\n| R\u003e | ( -- x ) ( R:  x -- ) | move x from the return stack to the data stack. |\n| R@ | ( -- x ) ( R:  x -- x) | copy x from the return stack to the data stack. |\n| RDEPTH | ( -- n ) | the number of single-cell values contained in the return stack. |\n| RDROP | ( -- ) ( R:  x -- ) | drop top return stack element. |\n| ROT | ( x1 x2 x3 -- x2 x3 x1 ) | rotate the top three stack entries. |\n| SWAP | ( x1 x2 -- x2 x1) | swap top two stack elements. |\n| TUCK | ( x1 x2 -- x2 x1 x2 ) | copy the first (top) stack item below the second stack item. |\n\n\n\n## TODO\n\nSome basic kernel operations need writing before work on the interpreter can be started:\n\n* ~~Scrolling TTY~~\n* ~~Control character output~~\n* ~~printf %d and %x formats~~\n* Debug printing\n* ~~Global Descriptor Table~~\n* ~~Interrupt Descriptor Table~~\n* ~~Interrupt Service Routines / Exception handling~~\n* ~~Keyboard driver readline input~~\n* ~~Memory allocator~~\n* ~~sbrk implementation~~\n* ~~libm implementation~~\n* ~~spinlock implementation~~\n* Fix compiler warnings\n* Build instructions for Mac/Windows\n* ~~assert~~\n* ~~basic linked-list, stack, queue, hashtable implementations~~\n* Virtual consoles\n* ~~Readline history \u0026 tab completion~~\n* Travis CI builds\n* ~~atoi,~~ atof, ~~strdup, trim~~ implementations\n* Extended memory / [Paging](http://wiki.osdev.org/Setting_Up_Paging)\n* Disk access\n* ~~Editor~~\n* Support ARMv7 architecture\n* Higher VGA display modes\n* Selectable keyboard maps\n\nInterpreter-proper tasks:\n\n* ~~Memory space~~\n* ~~Return stack~~\n* ~~Compiler~~\n* Expand word vocabulary\n* Unit tests\n\n## Contributors\n\nPull requests are always welcome. There is plenty to do, please let me know\nif you can help out; submit a request for commit access.\n\n## References\n\n### Forth\n\n* http://thinking-forth.sourceforge.net/\n* http://www.jupiter-ace.co.uk/index_Forth_general.html\n* https://en.wikipedia.org/wiki/Forth_(programming_language)\n* http://wiki.forthfreak.net/index.cgi?jsforth\n* http://www.complang.tuwien.ac.at/anton/euroforth/ef99/ertl99.pdf\n* http://www.bradrodriguez.com/papers/bnfparse.htm\n* http://colorforth.com/POL.htm\n* http://foja.dcs.fmph.uniba.sk/kompilatory/docs/compiler.pdf\n* http://yosefk.com/blog/my-history-with-forth-stack-machines.html\n* http://wiki.laptop.org/go/Forth_Lesson_0\n* http://pforth.googlecode.com/svn/trunk/fth/system.fth\n* http://www.forth.com/starting-forth/index.html\n* http://forth.sourceforge.net/standard/dpans/\n* https://groups.google.com/forum/?hl=en#!forum/comp.lang.forth\n\n### OS Development\n\n* http://www.cs.bham.ac.uk/~exr/lectures/opsys/10_11/lectures/os-dev.pdf\n* http://www.osdever.net/tutorials/view/brans-kernel-development-tutorial\n* http://www.acm.uiuc.edu/sigops/roll_your_own/i386/idt.html\n* http://wiki.osdev.org/Main_Page\n* http://wiki.qemu.org/Main_Page\n* https://web.archive.org/web/20090303224539/http://ibm.com/developerworks/linux/library/l-gas-nasm.html\n* http://www.mathematik.uni-bielefeld.de/~rehmann/Ckurs-f/b04/alloc.h\n* http://sourceware.org/newlib/\n* http://www.netlib.org/fdlibm/\n* http://geezer.osdevbrasil.net/osd/kbd\n* http://www.jbox.dk/sanos/\n* http://www.musl-libc.org/\n* https://www.linux.com/learn/docs/ldp/605-linux-i386-boot-code-howto\n* http://tldp.org/HOWTO/Linux-Init-HOWTO-3.html\n\n### ARMv7 Toolchain\n\n* http://www.kegel.com/crosstool/\n* http://wiki.lochraster.org/wiki/ARM7_GNU_Toolchain\n\n### Misc\n\n* https://github.com/orangeduck/mpc\n* http://libcello.org/\n* http://lists.cs.uiuc.edu/pipermail/cfe-dev/2008-August/002670.html\n* https://gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/Nested-Functions.html#Nested-Functions\n* https://en.wikipedia.org/wiki/VGA-compatible_text_mode\n* https://www.kernel.org/doc/Documentation/svga.txt\n* http://www.osdever.net/FreeVGA/home.htm\n* http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2015 Richard Hull\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frm-hull%2Fbyok","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frm-hull%2Fbyok","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frm-hull%2Fbyok/lists"}