68000 Tricks and Traps – Some assembly language programming guidelines (1986)
easy68k.com
easy68k.com
Ah, what wonderful chips the 68000 series were, at least for the era. So many registers, such a nice clean architecture. Good times.
One thing I didn't see mentioned is it had a small instruction pipeline so we could squeeze better performance out of it by by careful instruction sequence. For example you wouldn't load a register and then use in in the next instruction because it wouldn't be ready and could stall. By what is effectively interleaving code where possible you could keep it running flat out. Every cycle matters!
(Strictly speaking, the CDC 6600 didn't have load/store instructions per se. Instead, any time you modified address registers A1-A5, a load to the corresponding data register X1-X5 took place from the resulting address. Modifications to A6-A7 caused a store from X6-X7 to the resulting address. It made for such tight code!)
Fundamentally you load from memory in generated code by adding two numbers together (e.g. the struct address and field offset, array address and index...). Motorola figured that you could just pick one number from each of two sets and thus save two bits (i.e. the source registers could be encoded with 3 bits instead of 4) in the encoding for the instruction.
As far as CISC tricks go, it wasn't too bad. But it's aged poorly: no one would design a ISA like that today, while Intel's elaborate addressing modes introduced with the 386 are producing code size and cache efficiency benefits to this very day.
I've never worked on compiler design, does it really make it that much more difficult? I'd imagine that the compiler would have a clear idea of whether a value is a memory address or not and could simply put addresses in the address registers and data in the data registers but it's likely I'm missing something.
I'm not convinced it aged poorly. It failed because Motorola didn't have the resources to compete at keep up with Intel, and of course that could be down to the architecture making it harder.
But developments like [1] imply that this was more a problem with Motorola/Freescale's abilities to produce a sufficiently advanced design at the time - they're starting to beat Coldfire and PPC systems that are clocked far faster with the M68k instruction set on various benchmarks (though they are also adding instructions). With the caveat that this of course also tests things like memory bus speeds etc. What's clear, in any case is that the we never got to see what kind of performance it is possible to squeeze out of the M68k architecture.
Apart from the overly complex memory indirect modes, I'm having a hard time seeing how the 386 ModR/M and SIB setup is superior to what was in the 68020. Twice as many registers (though with usage restrictions), PC-relative addressing and a cleaner encoding. Those first two things have been fixed in x86-64 (and with generally fewer usage restrictions), but at the cost of making the encoding even worse.
At the expense of orthogonality, which I think is a great feature for a CPU to have and which the 68K (and 6809 and 6800) had in spades.
Having a flat 16 register file would require two extra register bits in most instructions which would either halve the number of possible operations or require bits to be removed elsewhere. Since the operations required on pointers is typically much smaller than those required on non-pointer integers, this setup makes a certain amount of sense. The big downside is that as ajross points out, it complicates register allocation in a way that just about no other "mainstream" architecture does.
Other tradeoffs (larger instruction word, fewer addressing modes on "normal" instructions, requiring an extension word for more addressing modes, etc.) could have produced a cleaner architecture at the expense of code density. Code density was a big deal in the late 70's when the 68000 was designed due to the cost of memory.
EDIT: A flat 16 register file would actually quarter, not halve, the number of operation types since you lose 1-bit per register field.
There are a bunch of other operations that you can't do on address registers (or at the very least, an address register can only be used for the effective address operand). This can be inconvenient if your code needs a bunch of registers, but not very many pointers. Not a huge deal otherwise.
But you can do that on the M68k:
SUBA.L <ea>,An
<ea> can be any addressing mode, including another address register. Most assemblers will let you use SUB.L and substitute SUBA if the destination is an address register.Didn't know how and why, but various conditional jumps used to plain fail. Conditions were met, but the jmp/je/jne/jz would not be executed.
That being said... The m68k... I was saddened to discover thst coldfire mcus had been discontinued, it would have been nice to play with an m68k-based board.
https://www.renesas.com/en-us/doc/products/mpumcu/doc/rx_fam...
MAP08 name inspiration? It's old enough