andi wrote:
You have to write instructions into RAM by hand.
This is indeed how early computers were started, but you may be assuming too much about the necessary steps. I'm not sure they even had microcode at the time. I don't know too much about that time, but I have gathered that the normal process involved "hand-assembling": Write your assembly language on paper, perhaps with one element per line (operation or operand), then write the octal code next to it.
Octal? There's no point using hexadecimal on a 17- or 23-bit computer,
and octal is easier to decode. You don't really want to write the extra instructions to convert hex when you're entering instructions by toggling front panel switches. (I assume. I've never actually done it.
) Why the odd and large numbers of bits? I've tried to design an 8-bit CPU a couple of times, and found that just trying to cram the design into so few bits makes a lot of work. You need to have experience and know tricks to do it. Then there's the addressing issue. For single-type languages, (i.e. simple ones,) you really want your word size to be the same as your address range.
andi wrote:
Question here is what language should your compiler target? I’m thinking maybe Forth or Lisp, but even those are a ton of effort.
No...
Download JonesForth and have a look at it. It's two files, one assembly language, the other Forth, with an extensive tutorial in the comments. If I remember right, it's about 2,000 lines *including* the tutorial. It's not a minimal Forth, and it's not even a compiler, it's an interpreter already. Forth is an astonishingly powerful and compact language, you can write everything from the very lowest level to the very highest in the same language, building higher and higher level constructs in the language itself. (JonesForth itself targets Linux, but plenty of interpreted Forths run on bare hardware.) Of course, at the lowest level you will need inline assembly language, but not as much as you might think. You can write your scheduler in Forth itself -- interpreted!
Lisp, on the other hand, is bloatware.
You need a lot of assembly language (or C) to get a Lisp system up, despite its simple syntax.
Note: an 8-bit Forth isn't really minimal. In fact, there's no such thing. On 8-bit hardware, the Forth is still a 16 bit language because its core is single-typed. You make other types with the language itself.
andi wrote:
I read that apparently C was originally written in BCPL but that in itself was influenced by ALGOL….basically, by the time C was made, people had long evolved past writing direct assembly, and were rather heading down the path of using existing compilers to make better compilers.
Not quite and definitely no.
Algol influenced many languages in the 60s, BCPL was just one of them. It was an interpreted language. Ken Thompson apparently didn't like BCPL's syntax, so he made a language with a minimal syntax called B. It was still interpreted and it had only one type. As the guys in the lab used it, they realised other types would be desirable. Dennis Ritchie implemented this, and he also wrote a (very slow) compiler, calling the new language C. It had no type checking!
I don't know where or when type checking was first implemented, but ANSI forced it into the language very much against the wishes of Ken and Dennis
. (I might be wrong, that might not have been one of the parts they argued about.) Eventually, they gave up fighting the standard. After that, they wrote Plan 9 exclusively using type-checked C! They also wrote very much faster compilers, but those didn't get open-sourced until 2000 so almost nobody uses them.
The "definitely no" part concerns the abandonment of assembly language. Many working programmers were programming for low-end hardware. I think they became the bulk of the programming work force in the 70s. They stuck with assembly language because no compiled language they could afford could possibly compete on performance, and performance was critical on that hardware. The first language to get into this segment was C, which became the most popular language and remained so until C++ took over in... 2007 I think.
The majority of programmers don't work in the fields of programming you hear about, they work in corporations making software for the corporation's own use. All the hype that's come and gone about Java and everything else has had relatively little impact on that field until this decade, when even embedded hardware became powerful enough to run comparatively bloated and slow languages like Python.
I haven't answered the original question. I don't want to answer it exactly, because designing an instruction set is quite a task on its own. Designing a *good* instruction set is up there with OS design. I've mostly been avoiding the question for this whole post.
I'll want to start with some real primitive hardware; 8-bit is cheap, not primitive. Let's have 14 bits at least; the same for data and address buses. There's no microcode, that won't be invented for another decade or two (I think). RISC hasn't been invented either, so the instruction set is technically CISC, but still simpler than such extravagant, luxurious designs as the 8086.
It was designed by someone more experienced than myself.
This machine isn't going to have a built-in screen because the hardware to drive it would be more complex than the computer itself. Instead, we have serial ports. A teletypewriter is connected to one of them. (We can't afford those flashy new "glass TTYs". Even if we could, we'd still need to print out our program listings so we could look at them properly.)
It's also got front-panel toggle switches because interfacing with a serial port is non-trivial especially when the data is coming intermittently from a TTY. There's no ROM to instruct the CPU to do that task.
So now, the program I personally would toggle into the front panel would be just enough to read octal from the serial port and write it into memory, if I type slowly enough. No buffer!
Typing in octal, I then input a better input program. It still accepts only octal, but lets me type faster and cancel a character or a line if I make a mistake. (Idea from Unix v6,
3rd Q here.) It still can't buffer more than one line, so now it prints a prompt to say, "your turn."
(At this point, I can very much see why they had punched-card readers. Typing into the tty could be replaced by inserting pre-punched cards. Mistakes could be fixed on the cards or new cards made. Carrying on without one.)
Now I write the primitives of a Forth interpreter. (Yes, I know it hasn't been invented yet.
) It's smaller than JonesForth but still a long slog, especially without macros. By the end of it, I can enter all characters and define what Forth calls 'code' words; somewhere between in-line assembler and the built-in functions of other languages. There is no assembler though; I'm so used to octal by this point that I just write octal straight into the definition.
(Ever used colorForth? Charles Moore wrote hex straight into definitions. Worse, you'll sometimes see cyan hex code in the middle of regular (green) Forth definitions with no explanation! In fact, before colorForth he abandoned Forth and wrote an OS with GUI elements in raw hex.
It was called OKAD. colorForth was basically the scripting language for OKAD2, the kernel of which wasn't in Forth. Even in this fantasy, I'm not yet as experienced as Charles Moore.
)
Now where am I? Oh yes, soon I can write normal Forth definitions, and can get on with the work of building up the system. I can even re-define words to add functionality or correct mistakes. What luxury!
I haven't mentioned permanent storage. I was thinking core memory which is non-volatile, but considering the lack of any sort of memory protection it would be much better to have a tape drive. This is connected to another serial port with some of what you might call GPIO to control the tape motor and switch between reading and writing. In the last phase above, I implement a tape driver and start recording the system onto tape with a rotating backup scheme. In future boots, I can 'just' toggle in a tape driver and load my previous work.
FinisThat was long enough
without designing an instruction set and its encoding! I'm seriously tired now. I think next time I'll quote a couple of sentences and just reply, "Dunning-Kruger effect detected."