2020-01-07 15:09:08 +01:00
|
|
|
## The Path to Self Hosting
|
|
|
|
|
2021-05-12 15:57:22 +02:00
|
|
|
Retro is an image based Forth system running on a lightweight
|
2020-01-07 15:09:08 +01:00
|
|
|
virtual machine. This is the story of how that image is made.
|
|
|
|
|
2021-05-12 15:57:22 +02:00
|
|
|
The first Retro to use an image based approach was Retro 10.
|
2020-01-07 15:09:08 +01:00
|
|
|
The earliest images were built using a compiler written in
|
|
|
|
Toka, an earlier experimental stack language I had written.
|
|
|
|
It didn't take long to want to drop the dependency on Toka,
|
2021-05-12 15:57:22 +02:00
|
|
|
so I rewrote the image compiler in Retro and then began
|
2020-01-07 15:09:08 +01:00
|
|
|
development at a faster pace.
|
|
|
|
|
2021-05-12 15:57:22 +02:00
|
|
|
Retro 11 was built using the last Retro 10 image and an
|
2020-01-07 15:09:08 +01:00
|
|
|
evolved version of the metacompiler. This worked well, but
|
|
|
|
I eventually found it to be problematic.
|
|
|
|
|
|
|
|
One of the issues I faced was the inability to make a new
|
|
|
|
image from the prior stable release. Since I develop and
|
|
|
|
test changes incrementally, I reached a point where the
|
|
|
|
current metacompiler and image required each other. This
|
|
|
|
wasn't a fatal flaw, but it was annoying.
|
|
|
|
|
|
|
|
Perhaps more critical was the fragility of the system. In
|
|
|
|
R11 small mistakes could result in a corrupt image. The test
|
|
|
|
suite helped identify some of these, but there were a few
|
|
|
|
times I was forced to dig back through the version control
|
|
|
|
history to recover a working image.
|
|
|
|
|
|
|
|
The fragile nature was amplified by some design decisions.
|
|
|
|
In R11, after the initial kernel was built, it would be
|
|
|
|
moved to memory address 0, then control would jump into the
|
|
|
|
new kernel to finish building the higher level parts.
|
|
|
|
|
|
|
|
Handling this was a tricky task. In R11 almost everything
|
|
|
|
could be revectored, so the metacompiler had to ensure that
|
|
|
|
it didn't rely on anything in the old image during the move.
|
|
|
|
This caused a large number of issues over R11's life.
|
|
|
|
|
2021-05-12 15:57:22 +02:00
|
|
|
So on to Retro 12. I decided that this would be different.
|
2020-01-07 15:09:08 +01:00
|
|
|
First, the kernel would be assembly, with an external tool
|
|
|
|
to generate the core image. The kernel is in `Rx.md` and the
|
|
|
|
assembler is `Muri`. To load the standard library, I wrote a
|
2021-05-12 15:57:22 +02:00
|
|
|
second tool, `Retro-extend`. This separation has allowed me
|
2020-01-07 15:09:08 +01:00
|
|
|
many fewer headaches as I can make changes more easily and
|
|
|
|
rebuild from scratch when necessary.
|
|
|
|
|
|
|
|
But I miss self-hosting. So last fall I decided to resolve
|
|
|
|
this. And today I'm pleased to say that it is now done.
|
|
|
|
|
|
|
|
There are a few parts to this.
|
|
|
|
|
|
|
|
**Unu**. I use a Markdown variation with fenced code blocks.
|
|
|
|
The tool I wrote in C to extract these is called `unu`. For
|
2021-05-12 15:57:22 +02:00
|
|
|
a self hosting Retro, I rewrote this as a combinator that
|
2020-01-07 15:09:08 +01:00
|
|
|
reads in a file and runs another word against each line in the
|
|
|
|
file. So I could display the code block contents by doing:
|
|
|
|
|
|
|
|
'filename [ s:put nl ] unu
|
|
|
|
|
|
|
|
This made it easier to implement the other tools.
|
|
|
|
|
|
|
|
**Muri**. This is my assembler. It's minimalistic, fast, and
|
2021-05-12 15:57:22 +02:00
|
|
|
works really well for my purposes. Retro includes a runtime
|
2020-01-07 15:09:08 +01:00
|
|
|
version of this (using `as{`, `}as`, `i`, `d`, and `r`), so
|
|
|
|
all I needed for this was to write a few words to parse the
|
|
|
|
lines and run the corresponding runtime words. As with the C
|
|
|
|
version, this is a two pass assembler.
|
|
|
|
|
|
|
|
Muri generates a new `ngaImage` with the kernel. To create a
|
|
|
|
full image I needed a way to load in the standard library and
|
|
|
|
I/O extensions.
|
|
|
|
|
|
|
|
This is handled by **retro-extend**. This is where it gets
|
2021-05-12 15:57:22 +02:00
|
|
|
more complex. I implemented the Nga virtual machine in Retro
|
2020-01-07 15:09:08 +01:00
|
|
|
to allow this to run the new image in isolation from the
|
|
|
|
host image. The new ngaImage is loaded, the interpreter is
|
|
|
|
located, and each token is passed to the interpreter. Once
|
|
|
|
done, the new image is written to disk.
|
|
|
|
|
|
|
|
So at this point I'm pleased to say that I can now develop
|
2021-05-12 15:57:22 +02:00
|
|
|
Retro using only an existing copy of Retro (VM+image) and
|
2020-01-07 15:09:08 +01:00
|
|
|
tools (unu, muri, retro-extend, and a line oriented text
|
2021-05-12 15:57:22 +02:00
|
|
|
editor) written in Retro.
|
2020-01-07 15:09:08 +01:00
|
|
|
|
|
|
|
This project has delivered some additional side benefits.
|
|
|
|
During the testing I was able to use it to identify a few
|
2021-05-12 15:57:22 +02:00
|
|
|
bugs in the I/O extensions, and the Nga-in-Retro will replace
|
2020-01-07 15:09:08 +01:00
|
|
|
the older attempt at this in the debugger, allowing a safer
|
|
|
|
testing environment.
|
|
|
|
|
|
|
|
What issues remain?
|
|
|
|
|
|
|
|
The extend process is *slow*. On my main development server
|
|
|
|
(Linode 1024, OpenBSD 6.4, 64-bit) it takes a bit over five
|
|
|
|
minutes to complete loading the standard library, and a few
|
|
|
|
additional depending on the I/O drivers selected.
|
|
|
|
|
2021-05-12 15:57:22 +02:00
|
|
|
Most of the performance issues come from running Nga-in-Retro
|
2020-01-07 15:09:08 +01:00
|
|
|
to isolate the new image from the host one. It'd be possible
|
2021-05-12 15:57:22 +02:00
|
|
|
to do something a bit more clever (e.g., running a Retro
|
2020-01-07 15:09:08 +01:00
|
|
|
instance using the new image via a subprocess and piping in
|
|
|
|
the source, or doing relocations of the data), but this is
|
|
|
|
less error prone and will work on all systems that I plan to
|
|
|
|
support (including, with a few minor adjustments, the native
|
|
|
|
hardware versions [assuming the existance of mass storage]).
|
|
|
|
|
|
|
|
Sources:
|
|
|
|
|
|
|
|
**Unu**
|
|
|
|
|
|
|
|
- http://forth.works/c8820f85e0c52d32c7f9f64c28f435c0
|
|
|
|
- gopher://forth.works/0/c8820f85e0c52d32c7f9f64c28f435c0
|
|
|
|
|
|
|
|
**Muri**
|
|
|
|
|
|
|
|
- http://forth.works/09d6c4f3f8ab484a31107dca780058e3
|
|
|
|
- gopher://forth.works/0/09d6c4f3f8ab484a31107dca780058e3
|
|
|
|
|
|
|
|
**retro-extend**
|
|
|
|
|
|
|
|
- http://forth.works/c812416f397af11db58e97388a3238f2
|
|
|
|
- gopher://forth.works/0/c812416f397af11db58e97388a3238f2
|