B4
b4 : a tiny forth-like virtual machine
Install / Use
/learn @tangentstorm/B4README
#+title: The b4 virtual machine
- Demo
[[file:ref/b4ix-rosetta.png]]
The above screenshot is the =b4ix= enhanced interactive shell. The sceen is broken into three sections:
- on top, a view into the systems video buffer, which is pre-initialized with a logo from the bios.
- in the middle, an interactive shell for the =b4a= assembly language.
- at the bottom, a view of stacks and section of the machine's ram
** explanation of the demo code
#+begin_src b4a
https://rosettacode.org/wiki/Loops/For
:E lb 'e io rt # set up ^E to emit a character :I cd cd du dc sw dc rt # set up ^I to fetch outer loop counter :loop du .f du ^I sb c1 ad .f lb '. ^E .n lb '| ^E .n zp rt 5 loop #+end_src
The =^E= syntax calls whatever function the =E= register is pointing at, and the assembler assigns it when it sees =:E=.
Here, =^E= loads the byte ='e= (quoted ascii char) and sends that as a command to the =io= op, which prints the next character on the stack.
The =^I= definition fetches the outer loop counter in a =.f= ... =.n= ("for/next") loop.
Since it's a function call, we have to dig deep into the control stack (=cd= means copy from control stack to data stack), (=du=)plicate the counter, and then (=sw=)ap it with the return address so we can push that back onto the control stack (=dc= means data -> control), and then =rt= (return).
Then =:loop= dupes its argument and uses it as an argument to the =.f=/=.n= loop.
During these loops, the loop counter is on the control stack, so =^I= grabs it as explained earlier, but there is also a copy of the original loop length (5 in this case) on the data stack.
so =du ^I sb= duplicates the 5, subtracts the outer loop counter, and leaves the result on the stack.
=c1= is an op that adds the constant 1 to the stack, and =ad= adds the top two values, so =c1 ad= adds 1 to the previous expression to get the length of the inner loop.
=.f lb '. ^E .n= prints that many dots.
=lb '| ^E .n= prints the pipe character and ends the outer loop.
then =zp rt= removes that original =5= that's been sitting on the stack the whole time (passed in when we explicitly called =5 loop=) and returns to the calling function (in this case, the interactive "b4ix" shell.)
- About b4
b4 is a tiny virtual machine, with a forth-like flavor.
There are currently five implementations:
- [[./jlang/]], implemented in [[https://code.jsoftware.com/wiki/Main_Page][J]].
- [[./pas/]], implemented in [[https://www.freepascal.org/][free pascal]].
- [[./lil/]], implemented in [[https://beyondloom.com/decker/lil.html][lil]].
- [[./js/]], implemented in javascript.
- [[https://github.com/tangentstorm/b4-gd][b4-gd]], implemented in GDScript for [[https://docs.godotengine.org/en/stable/][Godot 4]].
The implementations are kept in sync through the tests in [[./b4-tests.org]]
See [[file:./b4a/bios.b4a][bios.b4a]] for an example of b4 assembly language.
- Links
- [[https://github.com/tangentstorm/b4][b4 github repo]]
- twitter: [[https://twitter.com/tangentstorm][@tangentstorm]] / [[https://twitter.com/#!/search/realtime/%23b4lang][#b4lang]]
- reddit: [[http://reddit.com/r/b4lang][/r/b4lang]]
- Background
B4 is a forth-like virtual machine. Quick intros to forth (free and online):
- [[http://www.colorforth.com/POL.htm][Programming a Problem-Oriented Language]]
- [[http://www.forth.com/starting-forth/][Starting Forth]]
B4 was strongly influenced by the [[http://retroforth.org/docs/The_Ngaro_Virtual_Machine.html][ngaro virtual machine]] from retroforth 11, as well as the [[https://www.greenarraychips.com/home/documents/index.php#architecture][forth chips from greenarrays]].
