What we're gonna look at today is to pick up the story that we've been
involved in for quite a while now, of accidentally discovering that one has
written a cross-compiler. The first ever one I wrote - and I almost didn't realize
I was getting into it. For those of you have been following the story so far
I've been trying to motivate T-diagrams as a way of understanding compilers in
general, to illustrate the idea of moving compilers around or coping with hardware
that won't talk to one another. We did a "Before Arduino and Raspberry Pi". and we see
everybody speaks very quickly to each other nowadays. Was it like that then?
Not a chance! There wasn't a component - a universal
component - you could put in the middle that would bridge A to B in a very very
powerful way. For the infamous Linotype 202 jailbreak problem, that we've
covered a lot in videos, >> DFB: : This was one step before laser printers came on the scene
The trouble was that the 202 typesetter wanted everything down its
own, non-standard, parallel port. What I had to do was to commission a single
board Z80 chip. So, fairly low-level character-at-a-time stuffwas coming
down here. It was being sucked into the Z80 board as serial, because it was
simpler, but output as parallel, to be compatible with a parallel input port on
the Linotronic typesetter. I would point out that our bridging board
here was hardly high-tech. Steve Marchant, who built it for me, was a typical
electronics engineer: "You shouldn't be messing about with C, everything
could be done in assembler (!). I'm being very generous with you: I'm giving you a
2K ROM to put your program text in and if you can generate that out of C, and
not overflow, fine!" But also, bless him, he did give us an absolute lifeline which
comes off the top of this diagram. He did provide a monitor port from a VDU (if
you're in the UK - VDT if you're elsewhere in the world). A video display
terminal - dumb terminal - just showing you the flow of characters
into, and out from., And that saved our lives, many a time, in debugging what was
going wrong. The problem is that if you're going to put error messages out on
the VDT, they have to be stored somewhere. He provided us very generously with 2K
RAM - riches beyond the dreams! So yes - the 2K RAM got very full,
Because I remember Julian [Onions] who took this project over from me coming and saying
"We would get on very well if only we could do without the error messages for
the monitor port!" And I said: "We can't!" So, we phoned up Stevo who was not very
sympathetic and said it was all due to our being computer scientists and not
electronics engineers. And he'd given as a thing, for very good reasons where
at the low end of memory was our 2K of RAM. Sitting on top of that was the 2K of
ROM, in the memory space, which was actually reading the characters
preparing them for parallel, listening for responses - all this kind of stuff.
So, when Julian and I said: "Can you give us a more RAM?" do you know what he did? He gave us
2K more of RAM sitting on top of that lot. So our RAM holding was split into two.
"Never mind", said Julian quite rightly. He said: "We'll keep the lower level of
RAM for the actual buffering of the characters we'll keep all the error
messages in the upper bit". He said: " ... you know, frankly, we're only about 40 bytes
short of what we need, but we have to have more". anyway, we did our PLOD
interfacing program, wrote it in C, but the Whitesmiths system reduced
everything to assembler. So, they had their own Z80 assembler. So, you could
do 'assembler inserts' and these could be linked into your C-generated low-level
code, all in one big happy family. But, in the end, it got united into a single,
big, assembler-level programming and you ran the assembler. You were scarcely aware of
doing it because by this time it was all packaged up into a shell scripts. And you
just sort of ignored the detail and were happy for it to happen.
Physically, what happened was you prepared your program; you turned on
the PROM-burner. It was an EEPROM. An EEPROM is a
programmable read-only memory, electrically driven. You made a one-off
effort and you burnt your program in there. And you took it off to your target
board; you plugged it in; you hoped it worked. If it didn't work then there was
an electrically erasable option to it and you could reuse it. I don't know ...
I mean eventually I think it would have got 'tired' but I don't think we ever had to
use more than one. But anyway that was the way it worked. So it was a physical
transportation mechanism. You walked over; you put it [the EPROM] into the driver board and
you thought: "This time I've got it right - it's going to work!". Well, looking
at diagrams like this - even at the time I began to get quite philosophical about
this and [to] think: "Well, you know, there's so many questions you could ask here.
I'm sitting here producing my cross-compiled Z80 code and it *is*
cross-compiled because it's a different binary for the Z80 than it is on the
PDP-11, where it's actually being produced.
Wouldn't it be wonderful if only I could have far more memory, for data and the
program, on that board. I mean, 4K may be enough for an electronics engineer but
really, let's get serious, it's pathetic. I also thought well we do this and we
choose to come in and interface at the one character down a
parallel port level. Now, we knew, actually the Linotronic 202 typesetter was
front-ended not by a PDP-11 but by another 16-bit mini-computer. It was
called the Naked Mini. It was made by a firm called Computer Automation. It was a
16-bit machine; generally speaking it was slower than a PDP-11 would have been.
But it was adequate enough for the clunky electromechanical backing-and-
forwarding of bromide that the 202 had to indulge in. >> Sean: Linotype had bought in an
off-the-peg sort of solution ? >> DFB: I think the reason why it was called the 'Naked
Mini [was that] you could get a version with really no
frills and furbelows [e.g.] no case. It was a component you could build into a
bigger system, and all that. And everything you added on to it was an extra
(probably including the keyboard ?) Knowing that lot, But, you see, the more courageous
attitude, which Bell Labs did, but they had - how should we say, more experience
better skills and better lawyers than we had - is to say: "Blow this - that's not
really a very good place to intervene! Why don't we mount an invasion and
invade the Naked Mini and take it over completely?" And that's what Ken Thompson
did ,of course, in the Great Jailbreak. He got himself on there. His favorite
implementation language was the B language which - remember BCPL - B is the
first interpreted language - still typeless. C came along, developed mainly
by Dennis [Ritchie], but consulting Ken, to be *the* system implementation language.
So, Ken's first reaction on getting a strange machine is: "Right! I'll
look up how the assembler works; look at how the code is right down below and
overnight I will port my B interpreter and get it working on here". And, of course,
within a few weeks he'd got absolutely everything in there working off his cross
compiler, cross interpreter and everything. And, in many ways, that was the
way to do it because he could then decide: Do I port the whole software
mechanism onto that machine [Naked Mini] or would ibe better to say: " know enough, now, to
drive it directly from the PDP 11/44 and by-pass that [Naked mMini] largely? So, a lot of time was
spent with his software decoding what the heck the 202 was up to in terms of
rendering fonts and it took a long time to figure out what they were doing with
the characters and so on. So, it still prompts the issue: Do you invade the
enemy territory or do you stand off in the background and at arms length,
using tongs, just gently feed it the odd serial-line character.
and we had to, we just had to, take that latter view.
But with my thoughts about wouldn't life be easier if only I had a bigger Z80
memory. Could I actually host the compiler on that? Or would it be
hopelessly slow - yes it probably would (!) But, in theory, could I do it? Although
it's an 8-bit micro and appeared coincidentally, or not, in the Sinclair
ZX80 around about that time, there were a lot of people asking: "Ccould we
cross-compile stuff for the ZX80 and cross-compile it and run it? And at Cambridge,
at the time, there was a gentleman who will be known to many of you because he
became famous in the UNIX world. Steve Bourne. Steve Bourne is perhaps best
known for writing the canonical Bourne Shell that comes as part of UNIX. But
before he took the job at Bell Labs he was a PhD student and a researcher at
Cambridge and he wrote a system called Algol 68 C which was a dialect of the Algol 68
language. And his big aim, since Algol 68 was his baby, was - I can only imagine
because there's reports of these experiments going on - can i generate code
on here for the Z80 and what is the best way for me to do this?
So, all these Z80 boards were working with with Clive Sinclair and his boys, you
know, it will be lovely to be able to prepare lots of code for them. What's the
best way to do this? Well they had a great big IBM 360 machine and what they
discovered was their precious Algol 68 compiler and they went through all the
tricks we've covered in previous episodes of getting it to compile itself,
or getting it to compile a stripped-down version of itself, what they found was
that in the process of preparing a stripped
down version - if I've got this right - the actual compiler itself had to get very
big, for a while, in order that it could generate a smaller version that would
fit on the Z80 and when you say: "Well, what's 'very big' " 100K - and you
are limited by the architecture on a Z80 to 64K. There's no solution - you had to cross-compile.
Yeah?! And they did. But I think also, which is perhaps even more
interesting ... in fact I went to see Steve at the time and I don't know that I've
actually seen him since. This really was in the very early 80s, I remember it well,
I think he was back on vacation from Bell Labs. And he said: "You know, the
more you look at this business of transporting - or 'porting' as it is now called -
a compiler to a new environment, the more you realize what a mess we [can] get ourselves
into. We've got this language which gets compiled down close to binary on this
machine then we want to do it on another machine, like the Spectrum, and if we're
not careful we start all over again so we must do the whole chain. Must get
everything ready and all that. But he said: " ... y'know the hardest bit in writing
a compiler is not all the syntax analysis, and deciding what to do, it's
actually doing it in the code generator against an environment that can often
see very very hostile indeed. Wouldn't it be great if one could have a sort of
assembler-level vaguely "intermediate code" that everybody could use?" Now he was
one of the early people to realize this and he said: "I have invented this
thing called Z code. So my compilers now don't go to a specific binary in one
step, they emit Z code. And then, for the new machine, you don't have the whole big
compiler to transport. What you're saying is the Z code is the back end; the
syntax analysis and whatever is the front end. All you need to do, for a new
architecture is write a Z code compiler or interpreter" I said: "Zed code ?!"
He said: "Yes my new colleagues at Bell Labs want to call it Zee code and
I keep telling them I'm from the UK it's my baby it's 'Zed Code'!" This
approach, at the time, became so well known and so discussed that it even had
its own title: The UNCOL Problem. UNCOL, I think, stood for "Universal Computer Oriented Language".
The forlorn hope was that it might emerge from all those doing
compilers that there would be one superbly capable intermediate language
which every single compiling system in the world could subscribe to and be
happy with its facilities and so on. So, the search for the UNCOL solution.
Predictably it doesn't work like that. There's always enough difference in
architectures, and maybe even today, that it is not easy to have a one-size-fits-all.
So, I think this is a good place to draw a line for the moment. And so we've
got to investigate: how do intermediate codes work? how do they help you port a
compiler from machine A to machine B ? We vaguely see that it can obviously help
because all you're having to write, to get a foothold, is an intermediate code
interpreter for the new back-end and that gets you started.