Thought experiment: Bare metal to interpreter
Posted: Wed Jan 30, 2019 9:01 pm
Say you want to build an 8 (12 if it's easier) bit computer from scratch.
Assume most of the hardware is built (registers, ALU, bus, RAM, EEPROM, etc). However, there is no I/O. You have to write instructions into RAM by hand.
What opcodes should you implement in hardware? Then, using those opcodes, what form of I/O hardware could you implement to allow a user to (a) view what’s at a specific memory location and (b) set the contents of a memory location to a user-specified value, implemented via the opcodes you just defined (no cheating w/ an Arduino or ATTiny).
Once you can read/set memory using the computer, your next goal is to implement a higher level language, again using the opcodes you have at hand.
Alternatively: using your existing custom opcodes, write a separate program to communicate with another microprocessor, like an ATMega328, and send firmware to it via SPI or the likes that implements an I/O routine. This gives you a more powerful architecture (ARM) to work with, and should eliminate most hardware constraints as modern microprocessors seem like they should be capable of handling this. But remember, you can't have any existing firmware on it, except maybe the bootloader to allow it to accept new firmware over the wire.
I would guess the first step to take would be to make a simple assembler, in which you can write ASCII into memory via your I/O mechanism and then have a bunch of opcodes to convert your ASCII into machine code.
Armed with an assembler, you could begin to write a miniature compiler. Question here is what language should your compiler target? I’m thinking maybe Forth or Lisp, but even those are a ton of effort. 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. We don’t have that luxury though, we need to jump straight from assembly to compiler. So maybe we should also make a micro-language, that is just a few steps above ASM? I feel like this path has already been walked, but it was last walked several decades ago.
The ideal end goal would be to have a keyboard/display setup with a tiny REPL, running Lisp or one of its variants. With Lisp it would be very easy to implement everything else that’s missing in order to make this a “real” general purpose computer.
The biggest milestones in order would be (a) figuring out some way to implement I/O in the least amount of opcodes possible, (b) writing assembly to convert fake assembly into real assembly, (c) writing a compiler in assembly that is at the very least capable of generating better compilers, and (d) evolving those compilers to be able to write a Lisp interpreter and hooking that up to your I/O setup.
It’s definitely possible, since people obviously managed to do it (or else we wouldn’t be here), but the difficulty would be doing it without millions of man hours and sitting on the shoulders of giants. My big bet is that we can offset that effort using what we know now (and what we’ve learned from the past) to avoid all the time spent experimenting and using it to beeline from nothing to a working solution.
Essentially what I'm trying to do in the broadest sense is simulate the advancement of computer technology from the very beginning. Way before we had GUIs, keyboards, interpreters, compilers, hell, even punchcards.
How could we get from there to a little closer to now?
How would you do it?
Assume most of the hardware is built (registers, ALU, bus, RAM, EEPROM, etc). However, there is no I/O. You have to write instructions into RAM by hand.
What opcodes should you implement in hardware? Then, using those opcodes, what form of I/O hardware could you implement to allow a user to (a) view what’s at a specific memory location and (b) set the contents of a memory location to a user-specified value, implemented via the opcodes you just defined (no cheating w/ an Arduino or ATTiny).
Once you can read/set memory using the computer, your next goal is to implement a higher level language, again using the opcodes you have at hand.
Alternatively: using your existing custom opcodes, write a separate program to communicate with another microprocessor, like an ATMega328, and send firmware to it via SPI or the likes that implements an I/O routine. This gives you a more powerful architecture (ARM) to work with, and should eliminate most hardware constraints as modern microprocessors seem like they should be capable of handling this. But remember, you can't have any existing firmware on it, except maybe the bootloader to allow it to accept new firmware over the wire.
I would guess the first step to take would be to make a simple assembler, in which you can write ASCII into memory via your I/O mechanism and then have a bunch of opcodes to convert your ASCII into machine code.
Armed with an assembler, you could begin to write a miniature compiler. Question here is what language should your compiler target? I’m thinking maybe Forth or Lisp, but even those are a ton of effort. 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. We don’t have that luxury though, we need to jump straight from assembly to compiler. So maybe we should also make a micro-language, that is just a few steps above ASM? I feel like this path has already been walked, but it was last walked several decades ago.
The ideal end goal would be to have a keyboard/display setup with a tiny REPL, running Lisp or one of its variants. With Lisp it would be very easy to implement everything else that’s missing in order to make this a “real” general purpose computer.
The biggest milestones in order would be (a) figuring out some way to implement I/O in the least amount of opcodes possible, (b) writing assembly to convert fake assembly into real assembly, (c) writing a compiler in assembly that is at the very least capable of generating better compilers, and (d) evolving those compilers to be able to write a Lisp interpreter and hooking that up to your I/O setup.
It’s definitely possible, since people obviously managed to do it (or else we wouldn’t be here), but the difficulty would be doing it without millions of man hours and sitting on the shoulders of giants. My big bet is that we can offset that effort using what we know now (and what we’ve learned from the past) to avoid all the time spent experimenting and using it to beeline from nothing to a working solution.
Essentially what I'm trying to do in the broadest sense is simulate the advancement of computer technology from the very beginning. Way before we had GUIs, keyboards, interpreters, compilers, hell, even punchcards.
How could we get from there to a little closer to now?
How would you do it?