Chuck Guzis via cctalk wrote on Date: Mon, 10 Apr 2017 15:21:08 -0700
Thanks for the list--I was aware of the various Java
engines and the WD
P-code engine, but had never run into the SCAMP.
I just found an academic Pascal microprocessor from 1980 called EM-1 and
described all the way to the chip layout level:
http://authors.library.caltech.edu/27046/1/TR_2883.pdf
Okay, I've got to ask--exactly what made the 8086
unsuitable for C, but
work with Pascal? I'll admit to puzzlement about this statement.
I talked about the problem with far pointers and C in the post about the
iAPX 432.
The 64KB segments in the 8086 were not a problem for Pascal (or
Smalltalk, as shown by the Xerox PARC Notetaker computer) because each
heap object and each proceedure can live in a different segment to take
advantage of the whole memory. A single object (like an array) can't be
split into multiple segments which limits us to small objects (this is
not a problem for Smalltalk which can completely hide such splits as
shown in the Mushroom computer).
One big difference between Pascal and C is that while C seems to have
nested lexical scoped like Algol at first glance (and indeed it is often
list as being part of the "Algol family") it really doesn't. An object
either lives in the heap or is in the local stack frame. You can declare
new variables inside { ... } and they will shadow variables with the
same name declared outside of these brackets but this has no effect on
the runtime structures.
Pascal, on the other hand, allows proceedures to be declared inside
other proceedures and these nested scopes can access stuff declared in
the more external scopes. This requires some runtime structures that can
be awkward to implement in many processor architectures. An expression
like:
x := y;
might generate quite a bit of code if "x" was declared one level up and
"y" was declared three levels up. But on the 8086 we could have pointers
to the frames of the various lexical levels saved at the start of the
current frame just like the "display registers" in the Burroughs B5000.
We could have something like:
mov di,[bp-2*3] ; lexical level 3
mov ax,[di-20] ; y
mov di,[bp-2*1] ; lexical level 1
mov [di-8],ax ; x
Filling up those pointers on each proceedure entry can take some time so
a popular alternative for when nested references were not too common was
to have a linked list of runtime frames and code like:
mov di,[bp-2] ; lexical level 1
mov di,[di-2] ; lexical level 2
mov di,[di-2] ; lexical level 3
mov ax,[di-20] ; y
mov di,[bp-2] ; lexical level 1
mov [di-8],ax ; x
Being able to directly address constant offsets from the base pointer
and offsets from the result of that greatly reduces the number of
instructions needed to support lexical scoping in Pascal. For C,
constant offsets from a pointer are great for getting at the elements of
structs, so this is a nice thing to have in any case and most RISCs
implement this.
-- Jecel
p.s.: I haven't programmed in x86 assembly since 1987 so don't trust the
above code fragments