Bytecode Forth VM's?

185 views
Skip to first unread message

Paul Rubin

unread,
Sep 11, 2021, 6:21:03 PMSep 11
to
I may have asked this before, but do people here have favorite designs
for bytecode (aka token threaded) Forth VM's? Using something like MISC
seems too minimal. The idea is that having more bytecodes means shorter
byte-compiled code, but they also bloat the interpreter, so there is a
trade-off. The obvious idea of measuring compilations on a pile of
existing code isn't so great, because user code written for a given
compiler is likely to take the compiler's code generation into account.

Target cpu is AVR8 if it matters. The VM will have to be sparing with
code space on the target. The compiler would be on a remote host and
not face such constraints.

Anton Ertl

unread,
Sep 12, 2021, 6:39:44 AMSep 12
to
Paul Rubin <no.e...@nospam.invalid> writes:
>The obvious idea of measuring compilations on a pile of
>existing code isn't so great, because user code written for a given
>compiler is likely to take the compiler's code generation into account.

Maybe. However, I don't think it plays a big role. Perceptions about
what is supposed to be efficient play a bigger role than what is
actually efficient. And in any case, the requirements are most
important, and there are also considerations like maintainability or
religious beliefs ("thou shalt not PICK") that probably have a bigger
influence.

In any case, I would go with the measurements. What's the
alternative? If you implement, say, ROT inefficiently (because the
swap dragon hates jugglers) and communicate that, yes, maybe some
programmer would use ROT less, but I doubt that it would make much of
a difference.

- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard: http://www.forth200x.org/forth200x.html
EuroForth 2021: https://euro.theforth.net/2021

minf...@arcor.de

unread,
Sep 12, 2021, 12:01:14 PMSep 12
to
I forgot where, but somebody did statistics about occurence probabilities
of Forth words across a number of applications. That gives some indications
for a good selection of VM primitives, but nothing more.

If your applications are floating-point number heavy, or call external libraries,
you have to make your own design.

In my experience more attention must be given in the VM to error handling
and multitasking support, than for the set of bytecode operands.


Paul Rubin

unread,
Sep 12, 2021, 5:22:25 PMSep 12
to
an...@mips.complang.tuwien.ac.at (Anton Ertl) writes:
> Maybe. However, I don't think it plays a big role. Perceptions about
> what is supposed to be efficient play a bigger role than what is
> actually efficient.

Here I'm more concerned with code space than speed, partly on the theory
that if there is a bottleneck I can always write another primitive.
Code size at least is a clearly measurable objective.

The thing is, this Forth would be for use in a specific application and
really won't be used for running general purpose Forth programs. A
question like "should 2OVER be a primitive?" is affected by whether
2OVER is used much in the application. And that in turn is influenced
by whether the compiler supports locals.

The situation where the runtime interpreter is on a space-constrained
target but the compiler is on a remote machine and can be fancy, makes
sense for quite a few applications but doesn't get much attention on clf.

Paul Rubin

unread,
Sep 12, 2021, 5:31:39 PMSep 12
to
"minf...@arcor.de" <minf...@arcor.de> writes:
> In my experience more attention must be given in the VM to error
> handling and multitasking support, than for the set of bytecode
> operands.

Thanks, those are good things to bring up, and I will try to give more
attention to these issues. Is there particular wisdom about error
handling I should look at? If I have a multitasker, it would be a
simple one like eForth's.

minf...@arcor.de

unread,
Sep 13, 2021, 2:14:56 AMSep 13
to
That really depends on the target environment. For instance, the standard
exception wordlist doesn't know of exception classes, eg warning-alarm-failure,
and pertaining different exception handling routines. In a real world
application you will rather soon stumble over such things.

"Argument out of allowed range" could be an application exception, to be handled
by retrying an input routine.
"Missing opcode" is an internal VM exception, resulting in a core dump.
"User interrupt" could lead to a warm start.
"Timer overflow" in a multitasker could 'ring a bell'.
And so on...

To start with:
1) implement a catch/throw mechanism already in the VM
2) list all your possible exceptions and categorize them into severity classes
3) prepare the VM to handle different exception handlers

We know that the old Forth wisdom comes with "crash early".
But this is only a poor excuse for poor engineering.

Hans Bezemer

unread,
Sep 22, 2021, 12:40:57 PMSep 22
to
4tH's got about a hundred opcodes using a Harvard architecture. 2DUP will give you very little speedup over OVER OVER if you design the thing properly - and even less space. Note that even 2OVER has minimal space overhead, since you have to define it only once - then it's reduced to a single CALL.

switch() or GCC goto interpreters are quite fast (don't believe me - ask FICL). Tables with function pointers are slow - don't underestimate function call overhead in C. Some C compilers convert switches to jumptables, you see. If you want to avoid slow access in switches() anyways, get some stats about the frequency of keywords in Forth and organize 'em that way.

Hans

Hugh Aguilar

unread,
Sep 23, 2021, 12:36:13 AMSep 23
to
On Wednesday, September 22, 2021 at 9:40:57 AM UTC-7, the.bee...@gmail.com wrote:
> 4tH's got about a hundred opcodes using a Harvard architecture.

You don't know what Harvard Architecture is!

This is a kind of processor in which the code-memory and data-memory each have
their own address and data bus --- it is possible to access both code-memory and
data-memory concurrently.

The MiniForth is the only processor that I am familiar with that had a Harvard Architecture.
Every opcode executed in one clock cycle. It was reading the next opcode concurrently with
executing the current opcode (this was true even if the current opcode was accessing
data-memory). Note that there was no way to change the PC (program counter)
except with the NXT instruction --- this means that the next opcode in code memory is always
the next opcode to be executed --- there are no jumps or branches.

Hans Bezemer

unread,
Sep 23, 2021, 7:48:15 AMSep 23
to
On Thursday, September 23, 2021 at 6:36:13 AM UTC+2, Hugh Aguilar wrote:
> On Wednesday, September 22, 2021 at 9:40:57 AM UTC-7, the.bee...@gmail.com wrote:
> > 4tH's got about a hundred opcodes using a Harvard architecture.
> You don't know what Harvard Architecture is!
>
> This is a kind of processor in which the code-memory and data-memory each have
> their own address and data bus --- it is possible to access both code-memory and
> data-memory concurrently.

You can make up all the definitions you want, Hugh, but I'm going for this one: "The Harvard architecture is a computer architecture with separate storage and signal pathways for instructions and data. It contrasts with the von Neumann architecture, where program instructions and data share the same memory and pathways. In a Harvard architecture, there is no need to make the two memories share characteristics. In particular, the word width, timing, implementation technology, and memory address structure can differ".

Which is exactly what the segments in 4tH do. The Code Segment is R/O and contains opcodes and operands. The String Segment is R/O - and there are even NO opcode to access it directly. The Integer Segment contains cells, the Character Segment contains chars. All opcodes are bound to operate on their distinct segments. All addresses are for a specific segment.

> The MiniForth is the only processor that I am familiar with that had a Harvard Architecture.
> Every opcode executed in one clock cycle. It was reading the next opcode concurrently with
> executing the current opcode (this was true even if the current opcode was accessing
> data-memory). Note that there was no way to change the PC (program counter)
> except with the NXT instruction --- this means that the next opcode in code memory is always
> the next opcode to be executed --- there are no jumps or branches.

These are not specific for a Harvard architecture.

Hans Bezemer



Reply all
Reply to author
Forward
0 new messages