home .. forth .. machineforth mail list archive ..

[MachineForth] Rantings from a deranged lunatic

Round about 2AM this morning, I sat bolt upright in bed because the last
pieces had clicked into place and I understand. So I find myself in Jeff
Fox's usual state: hopping up and down about a new idea and so excited
that I can't wait to tell people about it. Since I couldn't get back to
sleep anyway, I thought I'd come annoy all you folks while the mood

The number one most important thing about MachineForth, and the thing it
took me the longest to get, is that it is simply an assembly language
for Chuck's chips. The fact that it happens to look a lot like Forth
is confusing at first, but not so important. Not that it's unimportant;
because it is a Forth, it is extensible. But it is first and foremost
an assembly language.

When you first look at MachineForth, what you primarily see is the A
register and how memory references are done via the A register. But
MachineForth only has the A register because Chuck's chips do; a
MachineForth for another chip would have a completely different set of
primitives. ColorForth on the Pentium has an A register only because it
is intended to model Chuck's chips.

My current project is a game for the Gameboy. Since I don't have a real
deadline or any real requirements, I figured this was a good opportunity
to play with Forth. Although I've done some work in Forth in the past,
it's been really limited; I've implemented a couple of Forths, but have
done no real projects in them. They've been used primarily as a
convenient tool for building throw-away diagnostics rather than as my
primary programming environment. Fundamentally, I'm a Forth newbie.

So I've been working on this thing I've been calling mf. It wasn't
originally called mf; I didn't call it that until I realized I was
moving towards a MachineForth-ish thingie for the Gameboy. A couple of
days ago, I realized what I really had was an assembler with a strange
syntax. That's when I realized MachineForth was an assembler with a
strange syntax for Chuck's machines. mf isn't a Forth; it's written in
C, so it's not extensible. That's why I say mf is MachineForth-ish
instead of saying it's a MachineForth. Perhaps my next generation will
be an actual Forth. But I digress.

Despite the simplicity and straightforwardness of mf, I was unhappy
with it. The code it currently generates is unnecessarily bloated. This
morning I realized what the problem was: I was needlessly attached to
the idea of a deep math stack. If I accept and live within the
limitations of the Gameboy CPU, I'll have much better code.

The Gameboy CPU is a modified Z80. Like the Z80, it doesn't deal very
well with slogging 16-bit data to and from memory. In fact, it's a bit
worse than the z80; some bright fellow decided that they didn't _really_
need LD HL,(nnnn) and LD (nnnn),HL. It's amazing how painful that loss
is. One thing the Gameboy really doesn't do well is have a second stack.
Sure, they've tried to gloss over the problem by providing predecrement
and postincrement addressing modes off HL, but you can only use them
with the accumulator. That makes moving a 16-bit value that way as
painful as not having the addressing modes in the first place; you have
to fetch things a byte at a time into the accumulator and then move them
to the appropriate place.

Somewhere along the line, I had seen a remark by someone who had used
the Z80's call stack for the math stack. He said it worked really slick
because the arithmetic primitives were small and fast. So I tried that.
But I also wanted subroutine threaded code. This meant that every
:-definition had to start with code to move the return address from the
call stack to the math stack. This might be a win if you're primarily
doing arithmetic, but all of the code I've designed so far is actually
dominated by calls, so it's not a win in my situation. Clearly, it is
inappropriate for me to use the call stack as the math stack.

However, the code to deal with a manual math stack on the Z80 is still a
mess and unnecessarily bloated. It had me thinking about doing the
project in straight assembly until this morning, when the answer came.

It's obvious now: use a fixed 3-level math stack. Top of stack is HL. 
Second on the stack is DE; you can add it to and subtract it from HL. Third 
on the stack is BC. This limits the amount of stack handling that needs to
be done to an acceptable level. All of the words I've designed so far
are shallow, anyway, and I suspect that if I have a word that gets
unacceptably deep I'll be able to split it into a couple of shallow
ones. And the register shuffling that needs to be done to treat them as
a math stack is no worse than the register discipline I've had to use in
other Z80 projects to keep things from getting out of hand.

Furthermore, a word can easily hide its internal stack depth from its
caller. If a word returns one cell, it can push DE and HL on entry and
pop them back into BC and DE (respectively) on exit; this hides the
depth of the word's internal calculations from its caller. The caller
needs to know how many cells the word returns (so it knows how deep its
own math stack usage is), but it needs to know that _anyway_.

So I've gone from something that had me wondering whether it was worth
using to something that is clearly not worth _not_ using.

As a side note, I also think I have some feel for what the minimum stuff
you need to do a Forth is, and it's a lot different than folks generally
think it is. Here's what mf knows how to do for a specific processor:

  - Generate a label
  - Generate code to load a literal
  - Generate code to call a word
  - Generate a conditional branch
  - Generate an unconditional branch
  - Spit out verbatim assembly code

It also knows how to copy comments from the source code to the generated
assembly code, but that is (strictly speaking) not _necessary_. Given 
these, all else follows.

Sure, mf has its limitations; it can't convert tail calls into jumps, for
example. But it's an excellent starting point and looks to be
well-suited for my current project. And it's changed the way I view the
universe, which is all anyone can ask from a learning experience.
Roger Ivie

To Unsubscribe from this list, send mail to Mdaemon@xxxxxxxxxxxxxxxxxx with:
unsubscribe MachineForth
as the first and only line within the message body
Problems   -   List-Admin@xxxxxxxxxxxxxxxxxx
Main Machine Forth site   -   http://www.