Reverse-engineering the register codes for the 8086 processor's microcode
righto.com
righto.com
Another source says "The actual internal representation is a combination of "microcode" and "nanocode". The 68000 has 544 17-bit microcode words which dispatches to 366 68-bit nanocode words." which sounds right.
Somewhere around here I have a very detailed article about this which might not be available online, but it would take some time to dig it up.
I've seen descriptions like yours saying that the microcode dispatches to the nanocode, but I can't figure out how to make both descriptions consistent. "The Architecture of Microprocessors" is extremely detailed, describing the action of each field at the bit level, while other sources are more hand-waving, so I'm more inclined to believe it. But I haven't looked at the 68000 closely, so I could be wrong.
This reverse engineering shows a surprising amount of exceptions. Here again, the crossover mux has 'relatively large transistors' and the bootstrap drivers come up again.
Is this still the case today? AFAIK, an FPGA design behaves like a pure digital device, apart from timing.
†See "Vonada's Engineering Maxims": https://twitter.com/kenshirriff/status/1633154548318732289
††The only "really" analog part of the 8086 is the charge pump to produce a negative voltage on the substrate.
There's a reason you can't just take a System Verilog FPGA and make an ASIC out of it that will work on the first time, and that there are entire teams and libraries to do it. And they'll still get things wrong that need to be fixed after they're discovered.
edit: the only reason we can blissfully ignore the underlying analog world is through the unceasing effort of asic designers, analog engineers, verification teams, firmware teams, and as a last line of defense, some poor bastard writing the driver to work around something that can't be fixed with any other method.
I believe that's Vonada's maxim #10 .....
It's worth noting that, had the mapping from segment registers to internal register numbers included i5, it would've been possible to access several of the other internal registers with undocumented instructions.
You still get only one instruction per cycle[2], but the circuit depth is lower and you can run faster. The tradeoff is that you need enough hardware on the chip to do all this at one time. The microcode solution can share resources between different instructions because they don't operate at the same time.
[1] This is more or less the original four-stage RISC setup. Modern CPUs have many more pipeline stages, including handling for things like L1 cache.
[2] Superscalar CPUs extend this idea by having multiple execution pipelines running in parallel, fed by an instruction fetch/decode unit that can figure out and emit more than one instruction in a cycle.
> RISC is about pipelining more than ISA, really.
I hesitate to get into a discussion about what RISC "really" is, but I'll point out that "IS" is the same in "RISC" and "ISA".
One big motivating factor for microcode is that it insulates the Instruction Set Architecture (ISA) from its actual implementation in hardware. That makes it a lot easier to be forward/backwards compatible.
Without microcode, you have a situation where every generation of processor, and even different implementations of a microprocessor will have different internal resources and circuits. You need to be able to control things inside the processor like the flow of data between registers, ALU(s) and the memory bus... But for each processor implementation, the available connections and execution units are going to be different. Microcode allows you not to expose all those underlying details to the outside. It's also more compact than having to directly control all of the connections inside of a CPU manually.
An alternative would be to have circuits that implement boolean logic and go directly from instructions bits to the internal control logic, but microcode also makes it easier to execute an instruction in multiple steps instead of being tied down to the constraint that each instruction must execute in exactly one cycle.
Microcode is effectively just a program. Can't you just write the same program in Verilog or whatever? I think the answer is "yes", but then you can't patch it afterwards, plus Verilog/etc didn't exist when microcode was invented.
Which I think is why microcode was invented – it was a big time-saver when circuit design was an entirely manual pen/paper process, and also it kept component counts down when the per-component cost was very high. Now we have HDLs, and transistor budgets in the hundreds of millions or billions, those reasons don't really apply any more.
But the need to patch post-shipment is even bigger than it used to be. As we put ever more complex features in silicon, the probability of bugs increases. With 3rd generation computers, you could always fix bugs by having a technician rewire some of the circuitry – more work than just replacing the microcode, but still feasible. It is completely infeasible to physically rewire the circuitry of a microprocessor, if you can't fix the problem in software (and microcode is ultimately a form of software), all you can do is manufacture a replacement then throw out the original.
> But for each processor implementation, the available connections and execution units are going to be different. Microcode allows you not to expose all those underlying details to the outside.
That's another reason which probably isn't as strong as it once was. In the 1960s, lots of software was written in assembler – having the same assembly language across the entire IBM S/360 line was a big win, since it made it easy to port software between machines, reuse skills, etc. Nowadays, very little code is still hand-written in assembler, almost all software is compiled from a high-level language – so if different machines have different ISAs, or (more commonly) a common ISA but with each machine implementing a different subset of it, and that forces you to recompile to move the code to a new machine – still somewhat of a burden, but far less than in the 1960s, or even 1980s.
Most CPU have a form of microcode in one place or another, often sequencing transfers between registers and buses.
Also, ISA compat is still crucially important. Maybe slightly less than before high level languages prevalence, but only slightly. You can only just recompile high level code if: * you have the source * you have a compiler for source to target * it is completly generic (e.g. no specific accelerator used)
In practice Windows on ARM shows that few people do it - even less so in a timely manner.
From what I understand, when the 8086 was being designed, the design was still mostly being done by hand, and the transistor budgets were still really small, so those two reasons for microcoding still applied. Things today are high much more automated and have much higher transistor budgets
> Most CPU have a form of microcode in one place or another, often sequencing transfers between registers and buses.
You need a control state machine, and you have two basic choices on how to implement it: microcode or random logic. Either way you will need registers (or something equivalent) to store control state
> Also, ISA compat is still crucially important. Maybe slightly less than before high level languages prevalence, but only slightly. You can only just recompile high level code if: * you have the source
Some of this is because OCO (object code only) software took over the market. I say “OCO” because in the 70s it was common for proprietary software to come with source - nobody called it “shared source” because it was just the norm which didn’t need a name. Indeed, when (in 1983) IBM stopped allowing customers source code access to their proprietary mainframe products, they had to invent a name for it (OCO). OTOH, unlike mainframe/minicomputers and commercial Unix, “secret source” became mainstream on microcomputers much earlier in their history. Also, in part this is because technologies such as OSF’s ANDF (aka TenDRA) never really took off, although WebAssembly may change that
> * you have a compiler for source to target
Not that big an issue given open source compilers (LLVM, GCC). Historically most vendors with their own CPUs had their own compiler development teams too (IBM, Sun, DEC, HP, Intel, among others). An incompatible ISA might nonetheless be just a small variation on an existing one so the necessary change to the backend might be small
> * it is completly generic (e.g. no specific accelerator used)
Many apps don’t use acceleration directly only through libraries (like crypto libraries using hardware crypto instructions)-again, a vendor with their own CPUs and compilers likely has these libraries too, and is responsible for changing them
> In practice Windows on ARM shows that few people do it - even less so in a timely manner.
Some of that’s because of the nature of the Windows ecosystem. Swapping CPU architecture on Linux is generally a lot easier, because many Linux hosts are 100% FLOSS except for the in-house apps they are used to run
No.
FPGAs are basically big fat lookup tables, some clever partitioning logic, and a boolean function. Inputs and outputs are (from the perspective of the "programmer") simultaneous, and if you want to do any state-keeping, it has to be done in response to some transition (such as a clock pin strobing).
State like registers. So you want to implement program registers and make those inputs be address and data lines, decode the instruction, map it to the appropriate internal "registers", then write out the data back to memory (if any), you're talking two transitions (or four if you want to reuse the address/data likes for fetch and load).
The speed/heat/power/price at which you can do that is (for the most part) a function of how big that lookup table is. If you can decode a single instruction in 4 steps instead of 1, you usually should because it means you can strobe 4x faster (or everything else will be cheaper, lower-power, cooler, etc).
Microcoding is a technique to doing this, but it's also a choice because there are limits to how little-power you can get, or how cheap fabricating any amount of silicon is, or even how low-level you can be meaningfully thinking about solving business problems, otherwise we'd all be using massively-parallel SBNZ-computers that float in the air.
I never said anything about FPGAs though. If you are telling me how microcode might be useful in overcoming limitations of FPGAs, I’m not sure what relevance that has to most microprocessors, which aren’t implemented as FPGAs
I expect this compactness -- or more specifically transistor count -- was a big driver of the design. Ken discusses the "hybrid" microcode of the 8086: Both more microcode or less microcode would probably have required more transistors than the final design incorporated.