• Updated 2023-07-12: Hello, Guest! Welcome back, and be sure to check out this follow-up post about our outage a week or so ago.

68020 Addressing Modes in CodeWarrior Assembler?

marciot

Well-known member
I have recently been doing some rather extensive assembly development on the Mac related to my MiniVNC project. One frustration is that while CodeWarrior Gold 8 supports the 68020 processor, it does not support the 68020 addressing modes. Does anyone know whether there is a version of CodeWarrior that does?

A better question might be, what is the best version of CodeWarrior for 680x0 development? What version has the best compiler and the best assembler? So far it appears as if versions of CodeWarrior after the one I am using just added bloatware like Java/Windows compilation without actually changing the 680x0 support.
 

cheesestraws

Well-known member
I don't have a specific answer for you as far as addressing modes go - but the CodeWarrior assembler for 680x0 was never really brilliant as far as I can see, and required rather ugly workarounds for common issues all the way up until they stopped doing 680x0 at all. So you may be out of luck.
 

David Cook

Well-known member
I noticed the same thing. I haven't had time to research a better alternative. MPW? Some version of Symantec C?
 

marciot

Well-known member
I've downloaded versions of CodeWarrior from Gold 8 (1996) through Pro 4 (1998) and as far as I can tell from reading the documentation, there were absolutely no changes to the 680x0 stuff in that time period. Which is a real shame, because I suspect adding those extra addressing modes to the assembler and making it feature complete would not have been very complicated -- I'm guessing less than a day of engineering effort. Considering that 68020 Macs came out in 1987, I really find it peculiar they never got around to doing that.

Personally, I really like Symantec C++. IIRC, I only switched to CodeWarrior because the version of Symantec C++ I had (version 7) lacked MacTCP headers, which I needed for this project and I also assumed CW was better since it came later.

Now that I have some more experience with both, I find CodeWarrior is lacking in the following things:
  1. It lacks an inline assembler (you can't mix C++ and assembly in the same function like Symantec C++ can)
  2. I've never been able to build an INIT using CodeWarrior Gold 8 (this is in part because of a possible bug in the version I have and also because #1 makes it harder)
  3. The compiler seems to use only three data registers, D0-D2. I do not know whether this is standard for the compilers of the era, but the 680x0 code CW generates can be beat by hand-coded assembly by anywhere from two to ten times, which is pretty pathetic!
I think now that I have more experience, it might be worthwhile to see if I can go back to Symantec C++ and see how it really compares. I do not know whether it supports 68020 instructions, but if it does, the issue with the MacTCP headers can probably be solved, while fixing the shortcomings in CodeWarrior cannot.

Maybe a fan-made "Symantec C++ Reloaded" needs to be cobbled together with updated header files from Apple or from MetroWerks so it could be the ultimate environment for 680x0 hacking! :)

It may also be useful to see whether a project like Retro68 might be the way to go. I am personally curious whether a modern gcc toolchain can optimize 680x0 code better, but since I prefer to develop *within* a classic environment with tools like ResEdit, I haven't really had the courage to try Retro68 yet.
 
Last edited:

marciot

Well-known member
After reading this MacWorld article, I think Symantec C++ 8.6 is seriously worth a look. I have been extensively benchmarking certain bits of code, in both C++ and assembly, so it would be fascinating to compare the CW and Symantec compilers to see which one is truly better.
 

marciot

Well-known member
Also, the following blurb in the MacWorld article is intriguing:
Symantec, belatedly recognizing some responsibility to rescue stranded Think Pascal users, has announced an agreement with Language Systems to make LS Pascal an add-in. In fact, the development environment has been designed to accommodate any kind of third-party compiler, so the millions of lines of FORTRAN code that still constitute much science and engineering software may find their way to the Power Mac through this Symantec backdoor.
I've definitely buy a beer to the first person who can take the GCC compiler from Retro68 and integrate it into the Symantec IDE! :D
 

Snial

Well-known member
3. The compiler seems to use only three data registers, D0-D2. I do not know whether this is standard for the compilers of the era, but the 680x0 code CW generates can be beat by hand-coded assembly by anywhere from two to ten times, which is pretty pathetic!
I think now that I have more experience, it might be worthwhile to see if I can go back to Symantec C++ and see how it really compares. I do not know whether it supports 68020 instructions, but if it does, the issue with the MacTCP headers can probably be solved, while fixing the shortcomings in CodeWarrior cannot.

Maybe a fan-made "Symantec C++ Reloaded" needs to be cobbled together with updated header files from Apple or from MetroWerks so it could be the ultimate environment for 680x0 hacking! :)
There's always a tradeoff between compiler code quality and speed. If I understand it correctly, CW essentially compiled to an intermediate form which then used a back-end to compile to a target CPU. That's why it competed well as a multi-language (C, C++, Pascal) to multi-target PowerPC, 68K, MIPS, Java compiler in the late 90s.

At the time there wasn't a standard asm syntax format, so maybe CW just dropped inline assembler and focussed on PowerPC compilation (with the standard ABI) at the expense of 68K compilation (with a working ABI), so I guess the D0-D2 rule is just something that works well with the back-end; and they didn't care about the 68K as it was already obsolete.

If we want a self-hosted compiler, then maybe LCC 4.x would serve as a reasonable ANSI 'C' compiler; it generates assembler source; is fairly small as a compiler and therefore perhaps a 68020+ asm could be hacked in with some kind of modern syntax? It's not C++, but the nice thing is that it's fast enough as a self-hosted compiler, so it'd be practical for 25+ year old Macs and people could then use Retro68 for extra performance?
 

marciot

Well-known member
There's always a tradeoff between compiler code quality and speed. If I understand it correctly, CW essentially compiled to an intermediate form which then used a back-end to compile to a target CPU. That's why it competed well as a multi-language (C, C++, Pascal) to multi-target PowerPC, 68K, MIPS, Java compiler in the late 90s.
I often hear that modern compilers can generate far better machine code than any human could, but I wonder whether that would hold true on the 680x0. I recall reading that part of the reason CPUs migrated from CISC to RISC was because it was easier to build an optimizing compilers for them. The 680x0 has a dozen ways to accomplish any given thing, each with vastly different execution times. I find myself benchmarking many ways to do the same thing and trying out sneaky tricks, such as using SWAP to store two unrelated values in a single register. The intermediate language CW uses (and likely modern compilers too) likely deals with simple operations that map far better to RISC than to CISC. Maybe it's unrealistic to expect any compiler to write good 680x0 code, a lesson I am re-learning for myself.

On the topic of assemblers, I did verify Symantec C++ supports all the addressing modes on the 68020, so it seems like a far better choice for 680x0 programming. I looks like a switch to Symantec C++ 8.6 is in my future.
 

Snial

Well-known member
I often hear that modern compilers can generate far better machine code than any human could, but I wonder whether that would hold true on the 680x0.
I've found that even a modern gcc compiler can't generate better microcontroller code than hand-optimised assembler, certainly for 8-bit AVR, Cortex M0+/M3/M4 or MSP430. Hand-optimised will be 2x to 3x faster and correspondingly maybe 2x to 1.5x shorter. This is mostly because on these MCUs you don't have to worry about scheduling; you can play fast and loose with the ABIs (as long as you conform when you finally call library functions and when you return to ABI conforming code); and you can generate code that's still decently structured without having to conform to high-level language constructs.

I recall reading that part of the reason CPUs migrated from CISC to RISC was because it was easier to build an optimizing compilers for them. The 680x0 has a dozen ways to accomplish any given thing, each with vastly different execution times. I find myself benchmarking many ways to do the same thing and trying out sneaky tricks, such as using SWAP to store two unrelated values in a single register. The intermediate language CW uses (and likely modern compilers too) likely deals with simple operations that map far better to RISC than to CISC. Maybe it's unrealistic to expect any compiler to write good 680x0 code, a lesson I am re-learning for myself.
Yes indeed. Also, as CISC CPU manufacturers started to try and compete with RISC in the late 80s, they started to optimise their simpler instruction forms for speed, which reduced the compiler gains from using some of the mid-to-late 80s instruction formats. E.g. some 68020 / 68030 instruction sequences that are faster than their equivalent 68000 instruction sequences become the slower sequences again on the 68040 (though I may be making assumptions here about the '040's microarchitecture). One other possibility is that CW figured the more complex '020 and '030 forms weren't worth it if the 040 was the target.


Section 10 is about 75% of the way through. As an example, MOVE instruction timings. You can see that the simplest memory addressing modes (An), (An)+, -(An), (d16,An), Abs.W, Abs.L and #<xxx> are all very fast; (d8,An,Xn) takes 3 clocks, but then the more advanced addressing modes suddenly take a lot of cycles to execute: 7, 10..12.

1706994568797.png
In addition, the complex forms have a tendency to muck up the pipeline, causing stalls. An optimising compiler might just dump the more complex forms, because it's easier to compose them from the simpler ones (though as you've noted, the CW compiler doesn't seem to use D3..D7 anyway).

On the topic of assemblers, I did verify Symantec C++ supports all the addressing modes on the 68020, so it seems like a far better choice for 680x0 programming. I looks like a switch to Symantec C++ 8.6 is in my future.
Cool. I wonder if the THINK C 5 compiler also supports those addressing modes in its inline assembler?
 

halkyardo

Well-known member
I've downloaded versions of CodeWarrior from Gold 8 (1996) through Pro 4 (1998) and as far as I can tell from reading the documentation, there were absolutely no changes to the 680x0 stuff in that time period. Which is a real shame, because I suspect adding those extra addressing modes to the assembler and making it feature complete would not have been very complicated -- I'm guessing less than a day of engineering effort. Considering that 68020 Macs came out in 1987, I really find it peculiar they never got around to doing that.

Personally, I really like Symantec C++. IIRC, I only switched to CodeWarrior because the version of Symantec C++ I had (version 7) lacked MacTCP headers, which I needed for this project and I also assumed CW was better since it came later.

Now that I have some more experience with both, I find CodeWarrior is lacking in the following things:
  1. It lacks an inline assembler (you can't mix C++ and assembly in the same function like Symantec C++ can)
  2. I've never been able to build an INIT using CodeWarrior Gold 8 (this is in part because of a possible bug in the version I have and also because #1 makes it harder)
  3. The compiler seems to use only three data registers, D0-D2. I do not know whether this is standard for the compilers of the era, but the 680x0 code CW generates can be beat by hand-coded assembly by anywhere from two to ten times, which is pretty pathetic!
I think now that I have more experience, it might be worthwhile to see if I can go back to Symantec C++ and see how it really compares. I do not know whether it supports 68020 instructions, but if it does, the issue with the MacTCP headers can probably be solved, while fixing the shortcomings in CodeWarrior cannot.

Maybe a fan-made "Symantec C++ Reloaded" needs to be cobbled together with updated header files from Apple or from MetroWerks so it could be the ultimate environment for 680x0 hacking! :)

It may also be useful to see whether a project like Retro68 might be the way to go. I am personally curious whether a modern gcc toolchain can optimize 680x0 code better, but since I prefer to develop *within* a classic environment with tools like ResEdit, I haven't really had the courage to try Retro68 yet.

I haven't had much exposure to CodeWarrior beyond reading and modifying some code from a CW project, but I can confirm that Retro68 is pretty good. I've been using it for the software components of my ethernet card project.

As you mention, cross-development is not without its inconveniences, but if put your source directory on a network share that's accessible to your old Macs, it works decently well. Resources are a bit of a pain to deal with, but Retro68's Rez tool is able to import resources from a MacBinary-encoded ResEdit file, so it's not impossible - personally I prefer to DeRez everything to text descriptions to make version control more straightforward. Unfortunately there's no source-level debugging facility at all, but it does at least generate MacsBug symbols.

As far as the quality of generated code goes, retro68's GCC seems to be pretty good, making good use of registers on the higher optimization levels (to the point of temporarily repurposing A6 if necessary) and emitting 68020+ instructions and addressing modes if you allow it to. Having inline assembler is definitely useful as well, although it's a 'you win some, you lose some' situation, since GCC's inline assembler syntax is, IMO, hideously ugly, and it lacks CodeWarrior's handy syntax for getting the offset of struct members.

Apparently it's also possible to run Retro68 on a PowerPC machine running OS X 10.4 or 10.5 and launch applications using Classic, but building the toolchain on an old PowerPC takes so long that I've never tried that option (and it's not particularly useful for an ethernet driver targeting 68k machines anyway).
 

joevt

Well-known member
I've used CodeWarrior for PPC assembly and MPW for 68K assembly.

I've also used CodeWarrior's 68K assembler (assembly function in .c source files) but don't remember using 68020 addressing modes.

I've built cdev, DRVR, INIT, FKEY, WDEF, etc. with MPW and CodeWarrior - whatever latest version that supports 68K. You don't need assembly to build most of those code resources.

CodeWarrior Pro 6 was the last to support 68K but you can maybe move the plugins to CodeWarrior Pro 7.

You can use MPW commands in modern macOS but I haven't tried to build anything with it. It works using 68K emulation. It's mostly seamless except all the commands must be preceded by mpw .
https://github.com/ksherlock/mpw
 
Last edited:

marciot

Well-known member
So I installed Symantec 8.6 and began compiling a list of differences. Unfortunately, there are pros and cons on both sides and whether there is a clear winner depends on which things are most important to you. Here is what I have found so far:

CodeWarrior Gold 8 (1996-01-04)
  • What I like:
    • IDE and icons looks more colorful and modern
    • Links and runs very quickly after single file change (< 1 sec for Hello World!)
    • Editor shows current line number
    • Excellent ANSI console window (SIOUX)
      • Supports scrolling
      • Can be integrated into Mac apps
      • Extensive customization
    • Uses Macintosh Programmer’s Toolbox Assistant/QuickView for documentation
  • What I dislike:
    • Cannot intermix assembly and C in one function (no inline assembly)
    • Assembler does not support 68020 addressing modes
Symantec C++ 8.6 (1997 Jun)
  • What I like:
    • Editor has vertical and horizontal split screen modes
    • Powerful inline assembly
      • Intermix assembly and C into one function
      • Full support for 68020 instructions and addressing modes
  • What I dislike:
    • Links and runs slowly after single file change (> 6 sec for Hello World!)
    • Inadequate ANSI console window
      • No scrolling or integration into Mac apps
    • Uses THINK Reference for documentation
      • Window can’t be resized!

The good news is that this latest version of Symantec C++ 8.6 does have the MacTCP headers that were lacking in Symantec C++ 7.0 (both it and CW 8 Gold now use Universal Interfaces 2.1) so I may be able to compile MacVNC under Symantec C++. The lack of a good console window is a huge problem though, as I am now using SIOUX in the latest version of MiniVNC for server logging and it would be hard to give that up.

I found the source code for SIOUX in the much latter CodeWarrior Pro 4 CD, so I wonder whether it can be backported to Symantec. Symantec C++ also has source code for their own console window, so perhaps it can be improved from that end as well.
 

marciot

Well-known member
I've built cdev, DRVR, INIT, FKEY, WDEF, etc. with MPW and CodeWarrior - whatever latest version that supports 68K. You don't need assembly to build most of those code resources.
It's possible that it was a bug in the particular version of CodeWarrior I was using (CodeWarrior 8 Gold, which is considerably older than CodeWarrior 6 Pro). I don't recall exactly what the issue was, but it was an problem with the entry glue code they provided that would always cause an link error.

I suppose I should try installing Code Warrior Pro 4 out of fairness, but I did check their docs and apparently the inline assembler still has the same limitations (although, perhaps by some miracle, maybe it was improved but the documentation was never updated to reflect that?).
 

marciot

Well-known member
Grrr, the "Disassemble" feature in Symantec C++ 8.6 gives me a "System error 10" under Mac OS 8.1

UPDATE: Incompatibility with "SOMobjectsTM for Mac OS", whatever that is!
 
Last edited:

Kouzui

Well-known member
I've been trying to do some C++ programming using Codewarrior 8 gold, and I was wondering if you guys might know how to import libraries into a project? For example, I'm trying to build a basic C ray-tracer as a kind of proof-of-concept, but I'm stuck on the part where I need to output the result as a png, and since I don't have the png.h file/associated library I can't do it.

I should also state that I'm trying to code for PowerPC but I assume the process is still relevant/useful for 68k.

I looked into png.h specifically and it was contemporary with Codewarrior so I don't think age/C standard is an issue.
 

marciot

Well-known member
I've been trying to do some C++ programming using Codewarrior 8 gold, and I was wondering if you guys might know how to import libraries into a project? For example, I'm trying to build a basic C ray-tracer as a kind of proof-of-concept, but I'm stuck on the part where I need to output the result as a png, and since I don't have the png.h file/associated library I can't do it.

I am watching this thread. In particular, I would be interested to know whether there was any Mac library standard and whether it is possible to mix and match libraries from different compilers (such as Symantec C++, MetroWorks C++ and Retro86). For the record, I did notice Symantec C++ 8.6 has a Metrowerks Library Converter tool, so I assume there isn't necessarily a common format.

I looked into png.h specifically and it was contemporary with Codewarrior so I don't think age/C standard is an issue.

I recently had to get ZLib working for one of my projects. What I did was I googled for the smallest implementation I could find simply added all the files to project. I imagine you can find a suitable PNG implementation out there.

If not, I would also recommend using a simpler format, such as PPM, which you can easily implement yourself:

 
Top