Fat Mac

About two weeks after you could buy them, I bought a 128K Mac and an external floppy drive at a Computerworld store in Monterey. At the time I was working on the Atari ST at Digital Research. I’d somehow latched onto the series of loose-bound chapters that would later become Inside Macintosh, and I really wanted to program the beastie.  I really admired the cleanliness of the internal design (compared to the internals of GEM), and I wanted to get my hands dirty.

But a clean design with awful tools isn’t a wonderful experience.

Programming the Mac proved to be more painful than I was willing to put up with. There was an assembler, but it was slow and every development turn required about 18 mouse clicks. I tried a version of MacForth and quickly remembered how much FORTH disgusted me. My roommate had more perseverance and actually wrote something — a terminal emulator, I think — in some interpreted Pascal environment published by Microsoft.   LightSpeed C and its awesome scale-of-seconds turnaround time wouldn’t exist for a couple of years, and you needed a ten thousand dollar Apple Lisa system to do “serious” development in native Pascal.

I upgraded the 128K Mac to a 512K “Fat Mac” over a weekend in one of the labs at Atari. You needed a pretty beefy soldering iron because the circuit board had massive +5 and ground planes that rapidly sucked heat away from pins you had to desolder. Getting the Mac apart took some ingenuity; Torx drivers were not common then, and the only one I could find was too short to reach the screw heads in their wells in the plastic case. I finally bought a too-short Torx driver anyway, extended it by ramming the barrel of a ball-point pen onto its handle, and used a pair of vice grips to apply torque.

But even having 512K didn’t solve the tools problem.  I wound up selling that first Mac within the year. I admired the Macintosh system software, and to some extent the hardware design (though the ST was even cheaper and leaner and arguably better if you just looked at the chip-level stuff and not the packaging). But actually developing on the thing was the misery of shoveling snow; tons of mouse clicks, no automation, lousy debuggers. I got my money back, and then some, with an ad in the paper.

About two years after that I was working at Apple, on tools.

This entry was posted in Rantage. Bookmark the permalink.

19 Responses to Fat Mac

  1. Arthur Langereis says:

    I got into (Mac) programming at around age 10 I think, 1990, using Turbo Pascal on a Mac ED (edu version of the 512K) that I got from my aunt who worked at a university. It was my first real foray into programming and I didn’t know about assemblers or anything like that so I just made these little programs that were useless to others but great fun for me.

    Moved to THINK Pascal not too long after and I started making some more exciting apps, now with GUIs, like DiskEraser (guess what that did, huh.)
    Then Pascal fell out of style and I moved to C(++) and CodeWarrior and later Xcode.

    I have to thank you for getting into tool-making, it is perhaps a rather thankless job sometimes (?) given how people always have complaints about their IDEs and such, but it certainly is so very important.

    What projects did you work on at Apple? MPW? Your stories are always a welcome read; thanks for your efforts, both in making tools and writing this blog.

  2. Kaishaku says:

    I was unaware that anything on the Mac was written in Pascal, but now twice in the past week I’ve heard reference to this. Googling for various permutations of classic Mac OS pascal doesn’t really provide any information OS-related, just lots of links to various compilers.

  3. munch says:

    Kaishaku,
    Mac development was assembler or Pascal. The development environment (MPW, which Landon worked on) did have a Green Hills C compiler early on, but most software was developed in Pascal. _Inside Mac_ described all the OS calls in Pascal and 68K assembler.

    It wasn’t until later (89/90?) that an internally developed C compiler was made available. And that compiler was written in — Pascal. The manager of the MPW tools group (Eagle I. Berns) made a bet (!) with Roger Lawrence that he couldn’t develop a C compiler in a year. Roger took the existing the Pascal compiler, re-used the backend code generator and plopped a C parser in front. He won the bet.

    As for C++, you don’t know joy until you’ve used CFront.

  4. landon says:

    @munch: I have to differ, you definitely *can* know joy, because that occurs when you turn off the computer, remove the disk that CFront is installed on and take it forthwith to a microwave oven. Ten seconds on “High.” Ahhhh… joy.

    My very first C++ program used multiple inheritance. CFront crashed and burned impressively. I’ve never felt comfortable using MI since (not necessarily a bad thing).

    @roger’s compiler: One of the Green Hills folks said to managers in MPW, “Anyone who says that he can write a C compiler in a year should be fired.” Roger won that bet, too. At least, he was still fixing C compiler bugs a couple years later 🙂

    MPW was a neat environment. Slow and idiosyncratic, but I’ve not seen the equal of the MPW Shell editor. (I nearly got a cow-orker fired when I egged him on to create keyboard macros . . . management found out about the feature he’d snuck in and he was in real trouble; the problem was, the end users *loved* them — “Best feature in MPW 3.3” said one of the folks in the OS group).

  5. @Kaishaku: For the first half a decade or so, almost all development for the Mac was Pascal. On the other hand, almost all development of the Mac was done in assembler, or at least hand-tuned code. I have no idea what exactly Microsoft used. I think even in the early days they were using P-code.

    My first Mac programming was HyperCard, then THINK Pascal. I think I used a BASIC somewhere along the line, too, but it sucked and I’ve purged the pain from memory.

  6. Atanas Boev says:

    Cool, go on! You can also consider cross-publishing mac stories at folklore.org

  7. Mark Poling says:

    “Torx drivers were not common then, and the only one I could find was too short to reach the screw heads in their wells in the plastic case. I finally bought a too-short Torx driver anyway, extended it by ramming the barrel of a ball-point pen onto its handle, and used a pair of vice grips to apply torque.”

    I love you, man!

  8. What is it that makes you prefer assembly to Forth? I’ve never written anything useful in either one, but I’ve fooled around plenty in both, and Forth seems a lot easier to read (if more difficult to write). What is it that I’m missing?

  9. landon says:

    @Kragen: It’s really, really hard for people to write good Forth.

    I know a couple of good Forth programmers. They are very humble about it. They are not one-language zealots. The projects they used Forth on, they thought about the problems they were facing and picked a good tool for the job. They use other tools, too.

    I know some more really awful Forth programmers. What they had in common was a frothing-at-the-mouth over-assessment of their toolset and skills. “We can do better work in Forth than any other language,” I’ve heard them say, which, given the quality of their actual achievements (versus the things they /thought/ they’d completed) was no-kidding laughable. These people aren’t programming, they’re jerking off.  It’s not pretty.

    Once you get around the social and management issues, it turns out that Forth has a number of technical problems. I’ll just mention a couple of them.

    For one thing, it is actually pretty slow on stock hardware. Bare, unoptimized stack machines suck pretty hard, and so do inner-interpreter loops [yes, I know about expanding directly into native JSRs — my very first Forth system did that]. It’s hard enough to write good, performant Forth that you might as well be writing assembly language and get an honest speed improvement.

    The Forth standard doesn’t have memory management, at least not in the sense that LISP, Java and C# systems do. This is hell on ADTs, for one thing.

    No exception support (that I know of).  Primitive scoping system.  Hidden global state maintained by the interpreter.  No standard I/O system (I could be wrong about this one).

    For me, personally:

    Forth doesn’t have named arguments — you have to keep track of where things are on the stack. This is mental overhead I’d rather not have to deal with all the time. Sure you could hack up your own little mini language to do this, but then you’d be inventing an environment.

    I hate C++ operator overloading (with a couple exceptions). And Forth seems to me to be mostly about inventing new operators, with wierd and wonderful names, all of which you have to remember. Walking into someone else’s program is like walking into a wall of things like “-()-” and “+zot” and “@^,”, and this is just misery.

    Finally, I know lots of people who write great, clear, commented assembly.  I’ve seen, written and maintained a zillion times more assembly than Forth.  While the law of crowds isn’t necessarily a valid argument, it’s still interesting why so many good programmers (who definitely know about stack machines and interpreters and so on, and could whip up a Forth implementation in like a day if they wanted to) pretty much ignore Forth as an alternative.

     

  10. @landon: So if I understand correctly, the first problem is that Forth encourages people to prototype things and think they’re done (“look! It’s a full object system with method calls, dynamic dispatch, and multiple inheritance in thirty lines of code! With no comments!”), the second problem is that Forth code runs a lot slower than assembly (or, usually, C — I’ve heard there are good optimizing Forth compilers but I’ve never used one), and the third problem is that it has all of the problems of assembly, plus the same kind of potential for obfuscation that makes C++ operator overloading unpleasant?

    That makes a lot of sense. I’ve certainly done my share of jerking off in Forth (not, fortunately, when anybody was paying me for the results).

    For me, I think the big difficulty is the absence of syntax, and the temptation to be too clever with the stack.

    I absolutely share your experience with knowing a couple of good Forth programmers who are very humble about their work and are not one-language zealots, although they do advocate programming languages sometimes. I have not reached the level of being a good Forth programmer. I have finally reached the level where I can write things as easily in Forth as easily as in assembly; I’m not yet sure about reading. I think I would have to maintain somebody else’s Forth code to learn that.

    About named arguments — I’ve seen a lot of assembly that’s written like this:

    mov winx,110
    mov winy,55
    mov winw,100
    mov winh,45
    call window
    add winx,2
    add winy,2 ;starting window
    sub winw,4
    sub winh,4
    call iwindow

    Do you think that’s good style? It seems pretty bug-prone to me, but it’s a lot more transparent than pushing the arguments on the stack or sticking them in registers.

    As an experiment, I recently wrote a compiler for a brain-damaged Forth dialect; it compiles itself (I wrote a bootstrap interpreter in Python) directly into x86 Linux ELF executables. Without the comments, it’s 117 lines of code (just over 3kiB). The code it generates is really unbelievably bad — at this point it’s in the “jerking off” category — but it’s self-sustaining, taking 2 million instructions per compile. I think that if I were stuck in a programming environment with no good tools, as long as I had at least, I don’t know, 12 kilobytes of RAM and some way to reboot when my programs crashed, I would sooner start with that than click 18 times to compile my program every time.

    It’s not likely that that will ever happen, of course. When I program for an 8MHz AVR with 128 bytes of RAM, I compile the code with GCC on a multi-gigahertz multi-gigabyte machine.

  11. I forgot to say: thank you very much for your clear and thoughtful response.

  12. landon says:

    @Kragen: That’s not very good assembly language style…

    In assembly, manifest constants save your life. Instead of “32” you use “MMU_ENABLE_BIT,” and so on. A constant like “45” demands a comment . . . and practically every line of an assembly program should have a comment. The better programs I’ve encountered do.

    The Macintosh sources for the 68K were very clean, and in assembly, and voluminous. I could probably hunt down some open source examples.

    [I had second thoughts about the phrase “jerking off” — while it accurately reflects some behavior I’ve seen, it’s too pejorative when all you’re really doing is experimenting or just horsing around. I’d reserve it for situations where you’re on the verge of defrauding someone who’s expecting you to do a job effectively.]

  13. I think those constants are pixel coordinates, so they’re somewhat less magical than MMU_ENABLE_BIT — if you lay out your window at (110, 55) there may not be any real reason behind those numbers other than that they look good. But there might be.

    Clearly comments explaining why the second window should start two pixels down and to the right of the first window would be helpful.

    Mostly what I wanted to ask about (with that example) was what you thought about the practice of passing procedure parameters in fixed memory locations like that. It seems to be pretty prevalent!

    Also, given that that code just passes parameters, do you think a comment per line is really called for? Maybe it would be useful to know what the author thought the other parameters to window were at that moment (the colors of various parts of the window), and maybe whether there was some logic behind the window position.

    Do you think people are writing new assembly code today that’s worth reading? It seems like most of its oxygen has been sucked away by C, and what’s left over is kind of abstruse stuff like linux-2.6/arch/x86/crypto/twofish-i586-asm_32.S. Maybe if I want to learn about good assembly style I should be reading Donkey Kong or the original Macintosh sources or FORTRAN II or something? Both Donkey Kong and FORTRAN II do have the voluminous comments you’re talking about; here’s a sample from FORTRAN II:

    ************************************************************************F0G04450
    * SUBROUTINE FOR STORING CHARACTERS IN TEXT TABLES. F0G04460
    * CALLING SEQUENCE TSX STORE,4 F0G04470
    * PZE LOC. OF CHAR.,0,NO. OF CHAR. F0G04480
    * TABLE OVERFLOW RETURN. F0G04490
    * NORMAL RETURN F0G04500
    STORE SXA AXR,1 XR2 CONTAINS THE 2S COMPLEMENT OFF0G04510
    SXA CXR,4 THE LOCATION OF THE SUBPROGRAM F0G04520
    STZ TMPF+2 NUMBER AND CAN BE USED TO OB- F0G04530
    STZ TMPF+3 TAIN THE LOCATION OF THE TEXT F0G04540
    CLA LCTXT+1,2 TABLE FOR A GIVEN SUBPROGRAM. F0G04550
    SUB LC1 INITIALIZE FINAL LOCATION WHICH F0G04560
    STA TMPF+3 CAN RECEIVE TEXT FOR THIS S.P. F0G04570
    CLA LSWRD,2 PICK UP ADDRESS OF FIRST OR LAST F0G04580
    STA TMPF+2 STORAGE CELL TO RECEIVE TEXT. F0G04590
    CLA 1,4 PICK UP LOCATION OF 1ST CHAR. TO F0G04600
    STA C4 BE MOVE TO TEXT TABLE. F0G04610
    ARS 18 F0G04620
    STO AC COUNT OF CHAR. IN CELL AC. F0G04630
    CAS LC6 TEST NUMBER OF CHARACTERS FOR 6. F0G04640
    TRA GREA6 NORMAL CASE MORE THAN 6 FOR ST.F0G04650
    TRA EQU6 SPECIAL CASE – EXACTLY 6. F0G04660

  14. Oops, sorry about the formatting. There were originally <pre> tags around that code…

  15. landon says:

    @Kragen:

    Mostly what I wanted to ask about (with that example) was what you thought about the practice of passing procedure parameters in fixed memory locations like that. It seems to be pretty prevalent!

    All I can say is: Yike! And also, “That’s so IBM 360.” The only other place I’ve encountered parameters-in-globals has been on small systems (e.g., 6502) where there wasn’t much stack, and reentrancy wasn’t a priority.

    The assembly with “every line having a comment” . . . yeah, maybe that’s overboard. The Mac ROMs had this, pretty near, because it was maintenance heavy code with a lot of people hacking on it.

    Then again, I saw an entire ROM cartridge (Atari Pac-Man for the 400/800 computer) that had exactly TWO comments.

    The happy medium is somewhere between the two.

  16. Thanks for all of your insights! The Donkey Kong source is indeed 6502, and uses parameters-in-globals everywhere, as far as I have read in it so far. (I’m not sure if this is the arcade version or not; I haven’t tried compiling it.)

  17. landon says:

    The DK sources you’re probably referring to are the ones for the Atari 400/800 computer system.

    The code doesn’t use the stack except for subroutine calls; lots of stuff is passed in globals (actually several sets of globals) because of the limitations of the processor and the memory available. To be fair, many functions also take arguments in registers, too. But frankly, there’s not much to work with.

    The spec that I wrote for DK was written in pseudo-C and “hand compiled” to what you see in the current listing (I still have the spec; I’ll dig it out and scan it in sometime).

    Pragmatically, most comments I’ve written for an assembly program have been to reduce the fear that I’ll come back to the code and not understand it later. That’s it. How you achieve clarity is your business — some orgs try to mandate “common procedure documentation patterns” and I’ve never seen a single success. Clarity and succinctness are part of the art.

  18. I think you’re right:

    ATARI CAMAC Assembler Ver 1.0A Page 1
    Donkey Kong Thur Feb 24, 1983 D1:HDR.

    I’d forgotten this was where I had found it!

  19. … and it looks like the whitespace in the code I’ve posted is actually preserved — all you have to do is “view source”. If you configured WordPress to permit attribute-less <pre> tags in comments, and restored the <pre> tags that were there, it would show up properly.

Leave a Reply

Your email address will not be published. Required fields are marked *