Sun, 25 Mar 2007

> I wonder if the Symbolics microcode was horizontal?  If they used
> vertical microcode while the Dorado was horizontal, maybe that might
> explain the difference between their perception of Moore's Law and
> Alan Kay's --- Kay consistently complains that modern CPU
> architectures run Smalltalk and other late-bound things slowly, which
> is sort of the opposite of the apocryphal Symbolics comment I cited
> earlier.

I don't know Kay's argument well enough to address it directly, but I  
believe a modern CPU architect would say the critical factor is to run  
fast stuff fast, so early-bound things go as quickly as possible, and  
late-bound things wind up going as slowly as necessary -- if the only way  
to make late-bound things appear to run in the same number of clocks as  
early-bound is to slow down the machine, that's a tradeoff they've thus  
far been unlikely to make.

(this implies there ought to be a hierarchy of binding: late-binding for  
code whose data lives on the net or on disk, early-binding for code whose  
data lives in L1 or in registers, and a suitable mix for everything in  
between)

But I don't think this is the opposite of the Symbolics comment:

> I have a vague memory that some of the Symbolics folks said that when
> they reimplemented their 36-bit CPU as an Alpha AXP program
> ("OpenGenera"), it fit in the L1 cache of the Alpha, and it ran Lisp
> programs about as fast as you'd expect microcode to run on a machine
> with that kind of clock speed.

The two closest references I was able to track down were:
http://www.unlambda.com/lispm/memo528.html
http://pt.withy.org/publications/VLM.html

My understanding is the first, AI Memo 528, was roughly the architecture  
for all the lisp machines with the possible exception of LMI's K-machine.   
(After reading Stallman's inspiration for GNU in the demise of the AI lab,  
I have to wonder to what extent the "AI winter" came about because lisp  
machines were sold largely to projects flush with Star Wars money?   
Afterwards, with no raygun, they appeared more exotic than practical -- I  
am personally glad to have picked the web over Lucid in the mid-90's.   
This hypothesis implies there should now be an "AI spring" with the modern  
DOD, which, at least in robotics and speech tagging (consider automated  
wiretaps), seems to be true)

The second was an abstract for a paper that was never written.  They  
appear to have coded in a style similar to microcode, making use of  
multiple dispatch, paying attention to cache conflicts, and requiring 64  
bit data paths.  Given that simulating hardware is an early-bound problem  
(and that they had a wider and faster machine than the one being  
emulated), it doesn't sound surprising they got decent performance from a  
modern architecture.

Squint at emulation just right, and it looks like programming in general.   
One has an abstract problem, for which one wants to compute an abstract  
solution:

     A ---> A'

which (if one is not EWD, who saw no need to suffer from the diseases  
which he studied :-) tends to involve using a concrete machine to  
calculate a concrete solution:

     C ---> C'

then coding the abstract into the concrete (A->C), and decoding the result  
(C->A)

     A ...> A'
     |      ^
     v      |
     C ---> C'

That is, we want to emulate the abstract computation with our concrete  
calculation.

I think I now understand why Dijkstra was interested in adjunctions: when  
F:A->C and G:C->A form an adjunction, then GF is a nice endofunctor, and  
GFGF => G(FG)F => GF reduces to another nice endofunctor, (and GFGFGF is  
indeed associative) so when we string a bunch of these together we get a  
monad.

> Maybe [debugging] accounts, in part, for the great interest in static
> correctness proofs in the functional programming community?  OCaml has
> a reportedly very nice debugger that works only with its bytecode, not
> with its native code, and they simply try very hard to ensure that
> they have the same behavior so you never have to debug the native
> code.  Having a static type system that permits type erasure without
> loss of safety helps with this.

Yes, exactly.  The way to debug easily is to behave exactly as above, and  
map between the concrete and abstract at each step (GF...GF).  An  
interpreter does this "for free", that is, ignoring execution time.  The  
way to run quickly is to erase the intermediate (normally identity)  
C->A->C steps, and run the problem strictly in the concrete domain  
(Gccc...ccccF).  Compilers do this "for free", but then if we want to look  
at "the middle of" the computation, we must then have a debugger to  
reconstruct the equivalent A' from any given C' (and possibly synthesize a  
new C'', should we alter A' to A'').

Horowitz and Hill point out that similar games are played in hardware with  
sequential PLDs -- if one has the gates, it's easier to make a strictly  
synchronous design which keeps its (abstract) outputs in the registers.   
If one doesn't have the gates, it's more efficient to make a design which  
keeps the bare minimum of (concrete) state in the registers.

-Dave

:: :: ::

> It's too bad gdb hasn't acquired a decent scripting language, all
> these years after the Plan9 paper (was it "Acid: a debugger built from
> a language"?)

Sounds like the right paper.  I wonder to what extent Forthers,  
Smalltalkers, and Lispers use the multilevel nature of their languages to  
script debugging?

> If I remember correctly, bass started out using ColorForth as a basis?
> I'm afraid it's been a number of years since I looked at it.  Is there
> a place to see it these days?

It was on a laptop that didn't survive the move, so now it's on a bare  
2.5" disk and a few backup CDs packed somewhere in the "cave".  (a  
basement area that supposedly contains supplies in case of nuke attack,  
but in the case of swiss tends to be used for wine, prosecco, and skis;  
and in the case of at least some americans is stuffed full of things  
which, had we had half a mind when moving, would never have been shipped  
across the atlantic in the first place.  What's the news on you two?  Is  
it BA?)

I should dig it out sometime and GPL it, but it never progressed much  
beyond what you've seen.  The register allocation wasn't for general use,  
but was to allow full bandwidth when doing sequences of loads and stores  
-- somewhat like how the concatenative people are experimenting with  
interspersing linear code with stack-shuffling.  I was happy fairly with  
the code, but never came up with an equivalently structured approach to  
data literals.  (or rather, never came up with an approach that didn't  
seem to eventually lead to a traditional language)  I was interested in  
YAML for this purpose before it grew; now it'd be tempting to just put in  
something JSON-like (which would require changing the code syntax to  
preserve duality) and call it done.

The fellow who provides my alpine elevation data uses a homebrew language  
(which he actually ported from moto to intel at some point) that wound up  
in a similar place, but as his interests are array processing and  
raytracing, he's never bothered implementing much in the way of data types  
either.

Someday, I'd like to look at the initialization stuff in Virgil to see if  
it'd solve one of the big problems: literals, like code, live in readonly  
("text") and are expressed abstractly; we'd like for the intermediate  
variable values which live in data to be expressed concretely.  I had a  
decorator kludge in bass for literals that was a half-assed approach,  
something more elegant would not only handle specializing data  
representations but would also be able to specialize code fragments so the  
same source might have several machine-code translations to run in  
different monads -- and at this point the problem is to avoid simply  
reinventing macros.

The effort to stay 1-1 (and to prioritize sequences over graphs) may just  
be too restrictive; the approach I would try now would involve an algebra  
whose top level values would still be hardware-oriented bytestrings, but  
whose intermediates could be more symbolic.  It still wouldn't be powerful  
enough to turn a declarative text into an FSM, but at least it'd be able  
to transpose a COND form into a decision table or do peephole tail call  
optimization.

> There's the apocryphal story of Leonard Zubkoff implementing a
> debugger in a weekend for a new platform, rather than waiting weeks
> for someone else to do the job; I wonder how much more or less his
> debugger contained than DEBUG.COM.

Probably much more -- RPG's story is that it was a "symbolic UNIX  
debugger": when one controls the compiler symbols are simple, and  
ptrace(2) breaks things up into a debugging process and a debugged  
process, which also simplifies things.  So I'd imagine it at least had  
symbols and breakpoints {go, stop, step into}, and probably had expression  
evaluation and possibly step over.  (step out requires parsing opcodes,  
but the RT was a RISC, which would have helped)

> What do you mean, "loops with tails"?  You mean that you don't tend to
> factor the code into a lot of small functions?

Calling a function involves a label, so lots of small functions would mean  
lots of labels, which is what we're trying to avoid.  The head of a loop  
requires a label, but any straight-line code we can tack onto the end  
doesn't.  So we tend to wind up with chunks that consist of reducing  
something to a canonical form (the loop), followed by addition of more  
data which will be reduced in another chunk (the tail).  I guess it's  
effectively an apply(Y, eval(X)) -- somewhat reminiscent of writing in sed  
and fairly reminiscent of the algebraists' habit of canonically splitting  
maps into projection followed by injection.

> I wonder why DEBUG couldn't rememember labels or breakpoints.
> FIG-Forth ran on the same hardware and remembered the names of every
> routine in the system.  Maybe DEBUG had to fit into a tiny static
> corner of a 64K memory segment, to avoid limiting its applicability to
> small programs?  But it isn't restricted to disassembling or debugging
> tiny-model programs.

Of course if I was going to write more than 512 bytes of code that way,  
and wanted an interactive environment, I'd probably wind up with something  
like a forth.  The history seems to be that DEBUG.COM, like EDIT.COM, was  
part of the "quick and dirty OS" that Microsoft bought, and had been  
written figuring that someone else would soon replace them.

> Have you been following Ian Piumarta's Pepsi/Coke/Jolt/Albert work?
> He's very much focused on questions like how to allow you to modify
> Array>>#at: at runtime without breaking everything.  (Of course, if
> your modification is broken, you will still have problems...)

No, thanks for the links!  I think the reason for the ST-80 spec in ST at  
the back of the blue book was not only because metacirculars are cool, but  
also because they did cross development/upgrades from time to time by  
building up a foreign image and a foreign VM inside the usual image, and  
then bootstrapping them to standalone.

> I also think that's the first 8-page conference paper I've ever seen
> that includes a complete and working (?) synthesizable CPU design (in
> noweb and Verilog) in the text of the paper.  (It is synthesizable,
> isn't it?  My Verilog is not up to snuff.  The actual Verilog seems to
> be about 240 lines.)
>
> It's too bad that he doesn't report on how much FPGA space it needed
> or how fast it ran.

True.  I think FPGA boards are pretty big and cheap these days (so it  
should be possible to "try it and see"), but haven't had the excuse to  
play with one.  Any recommendations from kragen-discuss?