22

The 68020 is an improvement over the 68000 because it includes new instructions, possibly better speeds and so on. The 68040 is an improvement over the 68020 again for the same reasons, as is the 68060 over the 68040.

But is there any incompatibilities which could keep code written for the 68000 from being run the same way on a later model?

5 Answers 5

31

There are a few incompatible changes, but after the 68010, most of them are surmountable (with a performance penalty) or would only affect operating systems, not applications (at least, not applications written to spec, with no invalid or undocumented opcodes or addressing modes).

  • 68010:

    • introduced support for the MC68451 MMU;
    • “MOVE from SR” became privileged;
    • the exception stack frame changed to support restarting the faulting instruction¹;
    • the exception vector table became configurable (it’s at a fixed address in the 68000).
  • 68020: fully backwards-compatible with the 68010 as far as I can tell; introduced support for FPUs (MC68881, MC68882) and the MC68851 PMMU (I don’t know whether the 68851 is backwards-compatible with the 68451, apart from the coprocessor interface which is different).

  • 68030:

    • integrated the MMU, but the integrated MMU isn’t compatible with the MC68851;
    • dropped a number of seldom-used instructions that had been introduced in the 68020.
  • 68040:

    • integrated the FPU, which wasn’t as capable as the MC68882; unsupported instructions were emulated with a severe performance penalty;
    • simplified the MMU, requiring changes in operating systems (as a result, as mentioned by traal, Amiga UNIX only works on the 68030).
  • 68060: dropped multiprocessor management instructions which had been introduced in the 68020.

ColdFire is a subset of the 680x0 so 680x0 binaries can’t be expected to run there as-is (but ColdFire binaries should run on a 680x0).

As mentioned by Brian H, one other change which wasn’t supposed to be backwards-incompatible but which did end up causing a number of programs to fail is the extension of the address bus from 24 lines to 32 lines in the 68020. See this answer for details.


¹ Before the 68010, Apollo workstations used dual 68000s to work around this limitation — one would run the OS and programs, halting mid-step on page faults, the other would fix up the page faults, so that the first could continue without noticing anything amiss.

6
  • 3
    One major practical issue with software compatibility going from 16-bit to 32-bit was programmers abused the upper 8-bits of addresses in code targeting the 68000, as described in retrocomputing.stackexchange.com/questions/6651/…
    – Brian H
    Jun 5, 2018 at 12:38
  • 2
    Due to differences in the MMU, Amiga UNIX (AMIX) can run on a 68030 but not a 68040. Jun 5, 2018 at 15:27
  • 1
    as far as I remember, 68060 also dropped 64bit integer multiplications and divisions what was a major pain-in-the-ass during my Amiga days :)
    – lvd
    Jun 5, 2018 at 23:27
  • 1
    Once again, Coldfire wasn't merely a subset, from my older investigations I remember it changed the way some multiplication instructions worked. Therefore not every 68k code could be executed on it (provided dropped instructions get emulated etc.)
    – lvd
    Jun 5, 2018 at 23:30
  • In principle, every introduction of new instructions and/or addressing modes creates a potential incompatibility, as there could be applications relying on these formerly unused or illegal opcodes to fail. See also xkcd.com/1172
    – Holger
    Jun 6, 2018 at 11:36
18

The 68k family is largely compatible between all the members. "Normal" application code can be written to easily run on all the members, unchanged.

There are, however, a number of subtle differences and pitfalls to watch out.

  • Some instructions were made privileged after the 68000/68008/68010, so are only accessible in supervisor mode (notably MOVE SR,<EA>)
  • There were some differences even between the 68008 and 68000 in the IPL (interrupt priorities) supported, and even between different pinouts of the 68008 (3 vs. 7 possible interrupt priority levels)
  • There are some subtle differences in the behavior when you push a byte to the stack (can't quite remember where and what exactly, just remembered "don't do it")
  • Some of the members (most of >=68020, except CPU32) will happily access words and long words on unaligned addresses, some others will trap out.
  • Cache handling, strategy, and size is different for all 68k members that have data or instruction caches. Also some cache-related opcodes were only available in >68030
  • Math co-pro support sort of was reduced from the original 68881/68882 towards the built-in co-processors on the later CPUs
  • PMMU on-board support also varies significantly between the later members of the family
  • Interrupt stack frame looks different starting from the 68020
  • 68020 added long relative addressing modes with larger offsets
  • PC-relative branches could be farther away than only one word size starting from the 68020 (This and the above allowed flat 32-bit programs to be fully position-independent, which was not possible before without trickery)
  • 68020 and later had bitfield instructions
  • 68010 and later had a VBR to allow shifting the vector tables away from 0
  • The CPUs that only had a 24-bit address bus (<=68010) obviously could (mis-)use the upper 8 bits of the address registers for other purposes because they were simply ignored for addresses - That clearly didn't work well on machines that had a full 32-bit address bus.

And some more I have probably long forgotten.

All of these were possible to work around if you kept them in mind. Most of them would not even be an issue in applications, but rather only in OS code. Some of them can be used by application code to find out what CPU we're running on.

If you count the "68080" (an FPGA-based re-engineered and much improved version of the 68k family) to the family built by the Apollo team, there are even more changes to list, like an equivalent to the Intel MMX instruction set.

10
  • 5
    The 68020-68040 included a rather interesting "double-compare-and-swap" instruction which involved six(!) registers which would atomically perform an operation equivalent to if (*p1 == v1a && *p2 == v2a) { *p1 = v1b; *p2 = v2b; okflag = 1;} else okflag = 0;. Such an instruction may be used by multiple processors simultaneously to insert or remove an item from the same linked list without having to worry about the list becoming corrupt (if two processors simultaneously try to insert an item at the same place simultaneously, one would update the list and the other would...
    – supercat
    Jun 5, 2018 at 15:51
  • 5
    ...harmlessly find out that the list had changed and it needed to re-read the links and try again. If memory serves, at the time of the 68020-68040, maintaining a doubly-linked list without such an instruction was expensive, but then someone figured out an algorithm to safely update doubly-linked lists using only a "single" compare-and-swap instruction. Since DCAS required expensive and complicated caching hardware, the ability to achieve the necessary semantics in software made DCAS impractical.
    – supercat
    Jun 5, 2018 at 15:57
  • 2
    @supercat The proper mnemonic for that instruction is CAS2, and I must admit I’ve never seen it in production code.
    – tofro
    Jun 5, 2018 at 16:13
  • 1
    The fact that other machines didn't have such an instruction meant programmers had to figure out ways around its absence. I don't know whether its performance on the 68020-68040 was good enough to make it useful, or was sufficiently bad that programmers would want to avoid it at all costs. Or perhaps it required additional hardware connections between processors that few systems bothered with. In any case, it's interesting that such a powerful instruction would get implemented and then abandoned, though even features that are popular for awhile (e.g. extended-precision floating-point math)...
    – supercat
    Jun 5, 2018 at 19:08
  • 1
    ...can end up getting abandoned if the quality of support for them falls off.
    – supercat
    Jun 5, 2018 at 19:08
8

In addition to the other excellent answers, sometimes the addition of caches could cause incompatibility.

The 68010 had a single instruction cache that couldn't really cause any problems. The 020 increased this to 256 bytes, and later CPUs had both instruction and data caches which were even larger.

The main fault encountered with instruction caches is with self-modifying code. This is where the program re-writes part of itself. This was a common technique in the 80s. It could be used to make copy protection harder to crack (because any code dump might not reflect the code being executed, and I believe Rob Northern Copylock used that technique), or for performance reasons with data stored in the op-codes of instructions with immediate operands.

With the 020 and above changes to code in RAM that was also in the cache would not cause the cache to be updated or purged. This was an issue for some Amiga and Atari ST software.

A related but less common issue is where data in the data cache does not reflect data written to RAM via DMA. Most systems avoided this by disabling the data cache for memory that could be accessed by DMA, such as chip RAM on the Amiga.

One Amiga specific issue was that on CPUs without cache or extra memory the operation of the blitter (an memory manipulation chip primarily used for graphics) could block the CPU entire so that no instructions were executed until the programmed blitter operation was finished, due to the CPU not receiving any memory access cycles. With the addition of an instruction cache the CPU could carry on executing instructions, for example re-programming the blitter mid operation.

Beyond caches, due to architectural improvements and higher clock frequencies software on later parts would run faster, which could interfere with timing in badly programmed software. That was the reason for the "turbo" button on PCs of the era.

4
  • 2
    The STe blitter also blocked the CPU, IIRC. I don’t know if there ever was a way to avoid that on the STs by using a cache though... (The TT avoided the issue by emulating the blitter in software.) Jun 5, 2018 at 16:04
  • @StephenKitt The ST used the 68000 which didn't have any cache so things could never get inconsistent. Of course if one upgraded the ST's CPU (which was not unheard of IIRC) then all bets are off. The TT, though, did have both cache and (multiple) DMA controllers but I'm not sure how it dealt with cache consistency. Pure conjecture but maybe TOS invalidated the CPU cache after getting an end-of-transfer interrupt? Jun 6, 2018 at 21:15
  • @Alex I was reacting to the description above of the Amiga’s behaviour with the blitter. I don’t think the idea of stopping the CPU while the blitter operated (on the Amiga or the ST) was to avoid coherence problems; it was just that the blitter took all the memory cycles so the CPU couldn’t read anything from memory. That doesn’t mean that the problem you describe doesn’t exist obviously! I don’t know how the TT dealt with cache coherence either. Jun 6, 2018 at 21:25
  • @StephenKitt Ah, got it. It makes sense that the blitter would grab the bus. I wish I could track down some better hardware documentation for the TT in specific. It's got a pretty interesting bus architecture but the service manual and the schematics leave a lot of how it works unexplained. Jun 6, 2018 at 22:45
8

But is there any incompatibilities which could keep code written for the 68000 from being run the same way on a later model?

Yes. Any 68000 program that used the "move from SR" instruction in user mode will trap on any later version of the processor from the 68010 onwards because the instruction was made supervisor only in that processor. This was to support virtualisation.

Also, the exception handling was changed to make certain exception conditions recoverable e.g. bus error which is necessary to support virtual memory. The content of the exception stack frame was changed to make some instructions restartable.

This means that any 68000 program that inspects the exception stack frame will break.

Another backward compatibility issue - actually probably the biggest at the time - Was the size of the external address bus. In the 68000, it was 24 bits, but addresses in memory and in registers where 32 bits. In the 68000 the upper eight bits of any address were simply ignored when placed on the address bus. Programmers frequently took advantage of this by using those eight bits for tagging. Any program that did that (and there were many e.g. early Apple operating systems prior to System 7 and Microsoft Amiga Basic) would break on a processor with 32 external address lines (e,g, the 68020).

Thanks to Julie in Austin for reminding me about that last point.

2
  • 2
    For the '010 and '020 the difference was more than "make it restartable". The '020 could restart in a completely different manner than the '010 -- there were multiple stages of execution and each of those could be restarted, one after the other. This is the sort of hardware level change that an application had better completely ignore -- as compared to abusing high-order address bits which developers seemed to love doing to save RAM. Jun 5, 2018 at 22:23
  • @JulieinAustin Thanks for that comment. I'm going to add the high order address bits thing to my answer,
    – JeremyP
    Jun 6, 2018 at 9:20
4

To start with, the 68040 integrated the FPU and dropped some (68881/68882) instructions. Similarly, the 68060 dropped in addition some 68020 instructions.

All of these changed/dropped instructions could be emulated on either CPU via dedicated traps.

For CPU32 and 5200 (Coldfire) core based controllers the case is different and code may need to be reworked, but the basic 68000 code can run on all of these CPUs without change.

2

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .