Published in 1989, this was the first book to explore the new breed of stack computers led by the introduction of the Novix NC4016 chip. The author commences with an overview of how stacks are used in computing, and a taxonomy of hardware stack support which includes a survey of approximately 70 stack machines past and present. Detailed descriptions, including block diagrams and instruction set summaries, are given for seven new stack processors from Harris Semiconductor, Novix, Johns Hopkins University/APL, MISC, WISC Technologies, and Wright State University. Major topics covered also include architectural analysis of stack machines, software issues, application areas, and potential for future development.
I read this in "dead tree format," not on a Kindle.
First off, two caveats:
* this is really esoteric stuff; if you're not a serious CPU architecture geek, this probably isn't anything that will interest you
* it was published in 1989, originally, so most of the references are to stuff from the 70s and 80s; it's somewhat dated; that's why I knocked 1 star off; I'd love to see an updated edition with newer designs explored
I may have a Computer Science degree, not an Electrical Engineering degree (most "serious CPU architecture geeks" are in that latter group), but I still found this interesting, partly because I've used / programmed computers with stack-based CPUs.
Most CPUs are register based; if you want to add two numbers, you move the numbers from memory into registers within the CPU, then you add the registers, then you move the results from registers back into memory. Everything has to go into a register, first. The more registers you have, the more data the CPU can keep "in its head" so to speak, and the less dependent it is on RAM. The x86 family has 6 general-purpose registers, plus a few special-purpose one. Many modern CPUs have over 30 such registers. What's the downside? If you want to switch tasks (which all modern computers do hundreds, if not thousands, of times per second) all of the registers have to be saved off to RAM, then then loaded with values for the new task, before you can actually do any work on the next task. More registers = more overhead on a task switch. Also, if you have 6 registers, you actually have 6 x 5 = 30 different MOVE instruction (from A -> B, from A -> C, etc.), and another 30 ADD instructions (A = A + B, A = A + C, B = B + A, etc.), another 30 SUB instructions (subtraction), another 30 CMP instructions (compare) plus 30 each for AND, OR, XOR, etc. This adds up to a lot of complexity in the CPU. Modern RISC CPUs, all register-based, have more registers so more register combinations (30 general-purpose registers means 30 x 29 = 870 each for ADD, SUB, MUL, DIV, CMP, AND, OR, XOR, etc.).
A stack-based CPU requires you to PUSH values onto the stack (whether actual numbers or values from RAM) and has one instruction for each of the above functions; ADD just adds the top two values from the stack, putting the result at the top when it's done. You can have a pretty deep stack, so you have a lot of values held in the CPU (in addition to whatever cache you may have) and the most-needed stuff is sitting at the top. Because the individual instructions are simpler, implementing a bunch of instructions is much simpler / faster. Because you don't have a ton of different ADD instructions the hardware needs to implement, you can do some very interesting things with your CPU design. You can have so many bits of your instruction indicating what ALU functionality you need to do (ADD, SUB, MUL, etc.), a few more bits indicating if you need to do some kind of comparison (CMP) and either a function call or return, all in ONE instruction. You can actually squeeze up to 3 different instructions into one 16-bit word; these can be run, in parallel, within the CPU, meaning you can squeeze more functionality into a given amount of RAM. Indeed, identical programs for CISC-based vs stack-based CPUs can give you 5 - 8x as much functionality in the same RAM. RISC-based CPUs (such as the ARM, used in all of the modern mobile devices) usually need about 2.5x as much RAM (and cache) as CISC-based CPUs, meaning stack-based designs are an order of magnitude more efficient with RAM.
Some stack-based CPUs actually let you put a small subroutine into the internal storage and run it as a single instruction. Because it's running entirely from the CPU's internals, instead of needing to load / run multiple instructions from (much slower) RAM, this run-time-assigned microcode usually runs about 2x as fast as an identical, external subroutine. Again, because the basic stuff is simplified, you have room to do more interesting things inside the CPU. Some CPUs have enough space that you can do this with MULTIPLE small subroutines.
Need to squeeze a lot of functionality into a small amount of RAM? Stack-based designs are better than register-based designs, CISC or RISC. Need to squeeze more speed out a smaller, lower-power-consumption chip? Again, stack-based designs for the win.
I've actually written code for Transputers, a family of stack-based RISC machines, in 1990. The T805, running 30 MHz, benchmarked about as fast as a 486 DX2-66, which hit the market 2 years later. Most multi-core x86 machines are lucky if 4 cores give you 3x the speed (3.0x performance / 4 cores = 0.75 = 75% linear speedup); Transputers were, routinely, hitting 90 - 95% linear speedup (20 cores = 18 - 19x real-world performance). Those were very-advanced little machines, made to be used as building blocks for high-performance compute clusters. Alas, they didn't run DOS, Windows or MacOS (Android didn't exist), so most people have never heard of them.
I've played with a Lilith, a Swiss-built computer which had a full GUI multiple years before the Mac or Windows; it had a CPU made up of multiple chips on a board (stack-based), with up to 128 KB of RAM. Pause for a moment and let that sink in; a desktop workstation, with a full GUI, years before the Mac, running in 128 KB (or less). All because the CPU could squeeze more functionality out of each KB of RAM. The CPU was designed with cooperative multitasking in mind, so it could respond, quickly, to an interrupt (data came in from the disk or the network, user hit a key on the keyboard or moved / clicked the mouse) and get back to the main application with minimal task-switching overhead. As a result, it was very responsive.
The modern GUI, as we know it, was developed on the Xerox Alto, which also had a stack-based CPU. Indeed, the Mesa CPU in the Alto had enough RAM built into it that you could load an entire Virtual Machine into the CPU (run-time-assigned microcode FTW) and it would run the VM bytecode as though it was object code, faster than any software-based VM running on a traditional CPU. That's part of how / why they could invent so much on that hardware, despite the fact it was developed / used in the 1970s.
Many of the rad-hardened CPUs used in modern satellites are stack-based, because they can squeeze tremendous performance out of very simple silicon (with very lower power consumption) and very little RAM.
Yes, it's obscure; most of the smartphone-swiping zombies in the world won't care. But, in certain niches, it's still VERY relevant. And, considering the RAM- and power-efficiency, it could become more-widely relevant again.
First few chapters give a good background into the different types of stack computers. But there is little attempt to show the differences in code that a compiler would have to produce. The latter chapters concentrate on the different types of processors with a few sample instructions. I would have liked to have seem more examples of the code that a compiler would produce for the different types of stack architecture, so that we could really understand the difference
Even though the subject can be quite engaging, the writing played against it. I guess that due to his engineering background this is somewhat expected, but the editors could’ve done a better job.