Re: [stack] Concatenative Hardware

"William Tanksley, Jr" <[email protected]>
Newsgroups gmane.comp.lang.concatenative
Message-ID <[email protected]>
Christopher Diggins <[email protected]> wrote:
> So I've been thinking about concatenative hardware lately. Here is a
> single-stack machine instruction set:

Interesting. I've played a lot with stack hardware (designed a
complete processor for a HW class), so your twist on the subject is
very thought-provoking.

> 0: JZ (val fxn -> ) // jump to fxn if value is below zero
> 1: CALL (fxn) // push return address and jump to fxn
> 2: LTEQ (val val -> bool) // compare values
> 3: AND (val val -> val) // perform bitwise and
> 4: XOR (val val -> val) // perform XOR operation
> 5: SHL (val val -> val) // shift-left
> 6: DUP (a -> a a)  // duplicate top-value
> 7: QTE (val -> fxn) // create a thunk
> 8: COMP (fxn fxn -> fxn) // compose two functions (append their contents)
> 9: POP (a -> ) // pop value from stack
> 10: DIP (a fxn -> a) // applies function to below top of stack
> 11: SWP (a b -> b a) // swap top two items

Very high-level... You'll need more detailed semantics for that to
work at all (memory management will be a BEAR for you). Of course,
you're entirely missing ADD and such. Oh, and I see you've got a
comparison instruction, but no conditional call or branch. I assume
you intended to imply those, of course.

You might want to look at Henry Baker's papers on a similar topic.
Check out his paper on O(1) instructions which could implement a VERY
flexible VM that doesn't require GC;
http://home.pipeline.com/~hbaker1/LinearLisp.html. "Hash cons"ing is
very important, and might even fit into hardware.

Once you get memory management a bit more simple, you need to
determine the implications of your instruction encoding. You don't
explain your encoding, which leads me to suspect that each instruction
is encoded as a byte. Needless to say, bit packing is a LOT nicer,
even when you're doing a VM.

The worst implication of your instruction encoding -- and this isn't
something you've made explicit -- is that your instructions _appear_
to be stored in CONS cells. This implies that there's one per cell.
That's MAJORLY inefficient in every way, needless to say. It's obvious
that one optimization would be to pack multiple instructions into a
single CONS cell, but that could well give you worse problems, as then
you have to decide how to handle CALLs. Perhaps the answer should be
that a CALL is always the CDR of a CONS pair...

> So essentially we can use the data stack also as a return address
> stack. This is a zero operand instruction set, so it is very compact
> and can be implemented efficiently, but it takes a lot of instructions
> to do simple things (e.g. accessing items deep in the stack).

"Doctor, it hurts when I do this." ;-)

It's possible that you shouldn't consider "accessing items deep in the
stack" to be a "simple thing".

> The "dip" instruction is so important I'm tempted to include variants:
> 12: DIP2 : (a b fxn -> a b)
> 13: DIP3 : (a b c fxn -> a b c)
> 14: DIP4 : (a b c d fxn -> a b c d)

The DIP instruction is so complex, high-overhead, and dependent on
precise details of user needs that I'm tempted to not include it.

> 15: open for suggestions

YES! 4 bits! (Assuming you don't want math or conditionals...)

> Of course "DIP" can be implemented as "SWP QTE COMP CALL", but I'm
> concerned about performance. The "DIP" is one of the most frequent
> instructions in my code.

It seems to me that DIP is inherently complex -- you don't want to
stretch your clock cycle to accommodate a single instruction. Much
better to let users implement DIP the way they need it.

Although I just noticed you use CONCAT instead of CONS. Hmm. That's
another inherently complex instruction (it takes linear time).

> Anyway, hopefully this makes sense to my fellow concatenators. I'd
> love to hear thoughts and suggestions. I'm pretty naive when it comes
> to hardware.

Think about this carefully... Generally speaking, the minimal
requirement for hardware is that all instructions should be O(1). I've
seen that requirement skipped... Chuck Moore's processors use cycle
times so fast that there's isn't time for the carry flag to propagate
on addition, so when you do addition you have to allow the stack to
settle in the ALU before you read the result of the addition (it's
simpler in practice than it sounds). Most CISCs have varying
instruction times. But in general it makes things messy.

Whatever you do, you do NOT want any single instruction to NOT take
constant time.

> - Christopher

-Billy
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.