What Woz Knew (and what didn’t foresee)


I spent the last week diving into how the Apple ][ worked, down to the level of 6502 microprocessor, systems design, and monitor assembly code, all trying to understand what Steve Wozniak (Woz) was doing differently than the other designers of that era, and what he would have done even different if he had hindsight from the early 21st Century.

First and foremost, what Woz accomplished with the tools he had in 1976 is amazing. He was a once-in-a-generation genius when it came to designing microcomputers. But he wasn’t all knowing nor all seeing, and with 40 years of hindsight some of his choices took me days to figure out.

Let’s start simple. Why did the Apple ][ display 40 characters on 24 rows? Timing. Woz set out to create a personal computer with “high resolution” graphics but at a price affordable to the masses. He chose the 6502 microprocessor because it was just $25, and know to be well worth that price in terms of speed and simplicity.

That chip ran at 1MHz. The RAM chips at the time had access times measured fast enough to not just support that speed, but more than twice that speed. Woz’s biggest breakthrough idea was to run the Apple ][ at 2MHz, split 50:50 between the 6502 running code and the rest of the machine using the same RAM to generate graphics.

Most of the complexity of an Apple ][ motherboard is devoted to generating those graphics. Woz started with a 14MHz crystal oscillator and divided up that master clock to get all of the timing signals needed to generate not only a standard color TV signal, but also down close enough to 1MHz to run the 6502 too.

The Apple II Circuit Description by Winston Gayler explains this in full detail, including all the math that ends up with 40 characters of text, each drawn as an 5×7 glyph (plus one empty column between characters), and 24 lines at the 60 frames per second framerate of American color TV. This math is the same as the 320×192 pixels found in Apple ][ HIRES video and 80×48 pixels found in Apple ][ LOWRES video.

In terms of graphics, all the Woz seems to have missed is how much simpler life would have been for every Apple ][ coder if he had made the addressing for text and graphics progressive from top to bottom, instead of the odd interleaving that every author attributes to “making the graphics simpler for Woz to implement” but which no one seems to be able to actually explain.

Moving on to systems architecture, I understand why Woz put ROM up in the $F000s, as the 6502 upon reset uses the last six bytes for interrupt vectors and the reset vector. Plus it makes sense to start RAM at $0000 and ROM and $F000 and meet in the middle.

I can imagine Woz back in 1975 with 4k or 8k of memory in his prototype boards (which were the Apple I) thinking that 48k was a massive amount of memory. This was, after all, a man who wrote a BASIC interpreter in less than 4K, without a real assembler to help. That BASIC needing only 4K of RAM to run as Woz’s breadboard Apple I only had 4K of memory.

What Woz didn’t foresee is that by the time I got my Apple ][+ in the early 1980s, the 48k of RAM the Apple ][ could hold would be not only ubiquitous, but yet-another 16K on the “language” card would be common. The trouble was, RAM and ROM met at the memory-mapped I/O $C000 address and thus Apple ][s and //es were limited to 48K of RAM without a lot of extra work for coders.

Given Apple’s enormous success, and similar success by the Atari 2600 and Commodore computers, all based on the 6502, what I don’t understand and what I asked in my last post is why there wasn’t a 6502 variant created with 24 bits of address space. If only Woz had pushed for that, we could have seen a successful Apple /// in the 1980s with megabytes of memory, a simple programming model, and perhaps a faster transition to virtual memory, concurrent processes, and the other operating system innovations that took until the 1990s or early 2000s, instead of millions of programming hours dealing with memory segments.

My other big “what if” thought last week was an idea that I don’t think Woz could have considered or would have liked. What if Apple had created an Apple ][ variant that had no graphics, no keyboard, and no more than one slot? For lack of a better name, my working name is the Apple //core.

The hindsight idea leading to that variant is the idea of Woz replicating his hardware genius for networking. Just as Woz had made floppy disks viable with the breakthrough Disk ][ design, what if he next did the same for networking. A Net ][ card with 1/10th the chips Xerox required for Ethernet or 1/4 the chips from the AppleTalk design of the 1990s.

Maybe that was beyond even Woz in 1978, but in some alternative history, after it’s IPO Apple could have purchased MOS from Commodore, Apple could have then pushed my 652402 chip into reality, and Apple could then have a Woz on staff with the ability to design his own chips. That alternative history Woz would have no doubt sped up the progress of personal computers, presuming Apple management let him play.

In any case, presume local area networking was a thing by the early 1980s. Apple could have then produced an Apple //core that was the first rack-mountable server. Just a CPU, memory, and networking chips. Maybe a tape drive until hard disks became affordable, but given a reason to make hard drives less expensive, I’ve little doubt Woz could have done to them what he did to floppy drives.

In my ponderings, I’m not sure a closet full of 6502s, even if they could be loaded with megabytes of RAM and even if they had access of megabytes of hard disk storage could be that useful, as digging into the MONITOR and DOS code for the Apple ][ made me far better understand why the term “structured programming” was repeated so often when I was learning how to program in the 1980s.

If you learned to code anytime after the 1970s, you likely can’t relate to what can be called unstructured code. The best way I can describe this is to imagine coding with neither subroutines nor blocks of code, but with many many globals. Here is how the ROM code for an Apple ][ begins (edited):

* Apple II            *
* System Monitor      *
*  *
* Copyright 1977 by Apple Computer, Inc. *
* All Rights Reserved *
*  *
* S. Wozniak          *
* A. Baum             *

LOC0        .eq     $00
LOC1        .eq     $01

            .org    $f800
f800: 4a           PLOT        lsr     A               ;Y-coord/2
f801: 08    php  ;save LSB in carry
f802: 20 47 f8                 jsr     GBASCALC        ;calc base adr in GBASL,H
f805: 28    plp  ;restore LSB from carry
f806: a9 0f lda     #$0f            ;mask $0F if even
f808: 90 02 bcc     RTMASK
f80a: 69 e0 adc     #$e0            ;mask $F0 if odd
f80c: 85 2e        RTMASK      sta     MASK
f80e: b1 26        PLOT1       lda     (GBASL),y       ;data
f810: 45 30 eor     COLOR           ; xor color
f812: 25 2e and     MASK            ;  and mask
f814: 51 26 eor     (GBASL),y       ;   xor data
f816: 91 26 sta     (GBASL),y       ;    to data
f818: 60    rts

The lack of documentation is justified by the fact that this was written years before floppy disks were available. Woz hand assembled a first version of this on another computer until he could then test and edit this on an actual Apple I and then Apple ][ prototype. In one of the reference books he talks about writing BASIC using only the mini-assembler in this ROM, and thus he likely wrote this ROM using that same mini-assembler, loading this file from a cassette tape (if not a version that had no comments to make it smaller), if not simply making hand-assembled changes live on the computer while editing this file separately on paper, and later re-typed into a text file.

No matter the process, what surprised me in reading this is that its a jumble of core operating system functions. Jumble as in little to no logical order. It starts with PLOT, which draws a line in HRES graphic mode. Logically, I was expecting keyboard input followed by text output, then maybe cassette tape loading and savings, then the monitor and mini-assembler, and only then graphics.

While I said there were no subroutines, that isn’t totally true. GBASCALC is a subroutine. So is PLOT. What makes this “unstructured” is that there are branches and jumps in the middle of what we’d consider a subroutine. What took a few hours to understand is that all of the labels like PLOT, HOME, CR, LR, SCROLL, etc. are addresses that are published for developers to use. The reference books expect you as a programmer to call these directly. If you want to clear the text screen on an Apple ][, ][+, //e, etc., you JSR $FC58.

fc58: a5 22        HOME        lda     WNDTOP          ;init cursor V
fc5a: 85 25                    sta     CV              ;  and H-indices
fc5c: a0 00                    ldy     #$00
fc5e: 84 24                    sty     CH              ;then clear to end of page
fc60: f0 e4                    beq     CLEOP1

fc62: a9 00        CR          lda     #$00            ;cursor to left of index
fc64: 85 24                    sta     CH              ;(ret cursor H=0)
fc66: e6 25        LF          inc     CV              ;incr cursor V(down 1 line)
fc68: a5 25                    lda     CV
fc6a: c5 23                    cmp     WNDBTM          ;off screen?
fc6c: 90 b6                    bcc     VTABZ           ;  no, set base addr
fc6e: c6 25                    dec     CV              ;decr cursor V(back to bottom)
fc70: a5 22        SCROLL      lda     WNDTOP          ;start at top of scrl wndw
fc72: 48                       pha
fc73: 20 24 fc                 jsr     VTABZ           ;generate base address

There are vertical spaces between many of these subroutines, but not always. In the above example, you can JSR $FC62 to draw a carriage return to the screen, or JSR $FC66 to draw a line feed. CR is just two extra instructions that drop into LF, and both drop directly into SCROLL, which you can JSR $FC70 too if you want to scroll up the screen.

What caught me in trying to understand this code were lines like $FC62. Two instructions earlier, #$00 (zero) was loaded into register Y. That value was then stored in a global named CV. Then BEQ is break if equal, which must be true. So why the break instead of a jump? Because in the 6502 the break instructions are one fewer bytes than a JMP or JSR instruction and also run one cycle faster. JSR and RTS are the slowest of all instructions, which is why this code is fully of branches instead of subroutines, why the code branches and jumps between subroutines, and probably why some of the subroutines were never reordered, as those branch instructions can only jump forward or backward 127 memory locations.

Basically, one of Woz’s clear goals was to squeeze as much functionality as he could into the 12K he set aside for ROM. Back to 1976, he was working on the Apple I that had 4K of RAM, and which had just 2K of ROM. That computer loaded programs from cassette tapes at a speed measured in kilobytes per minute. He must have worked on the ROM from $FF00 down to $FD00, then later when he wanted to add graphics, he dropped the bottom of ROM to $F800. PLOT is probably the last bit of code he fit into ROM, which is why it is the first function listed.

I wonder how many iterations it took to get PLOT to fit? Maybe that is why it uses the carry flag as a parameter, because anything simpler just didn’t fit into ROM?

I first learned how to code in my 7th grade pre-Algebra math textbook, which had one keyword of BASIC in between each chapter. I thus learned a more structured version of coding first. Later I learned assembly, and used it from time to time in my twenty year career as a software developer, but I was already proficient with Pascal and C before that career started and thus was missed this era of unstructured, every-byte-counts assembly coding.

Finishing up this week of nostalgic what ifs, I had two other thoughts.

One, what if someone came up with a language with the structure from C but the level of assembly? Take away all the branches and jumps from assembly code, replacing them with if’s, {}’s, and functions from C, complete with self-documented function arguments and return codes. Variables are then _a, _x, and _y on a 6502, corresponding to the three registers, $nn in a zero page address, or $nnnn for any other address. Inside these functions are a mix of statements like _a = $nn + $mm, which get compiled into assembly and psa, which are just assembly instructions. I suspect the language designers didn’t see structure and syntax as two different areas to play with separately. Or maybe the people building assemblers were themselves so experienced in unstructured code that they didn’t see how much if… then… else makes programs more understandable and maintainable.

Two, what if open source had arrived sooner? Thanks to the internet I found dozens of Apple ][ reference books from the 1970s and 1980s, none of which I had seen back then. The level of detail is incredible, down to the hardware layout, down to descriptions of how to use all the code in the MONITOR, and every detail you need to write your own disk operating system. That made me wonder what if Apple’s DOS 3.3 itself were published as source code? Written in some language like I describe above, so that it could be easily modified by others? Would we then have seen Apple DOS running on Commodore 64s and IBM PCs? Would Microsoft even been asked to write IBM’s DOS, or if so, would they have to have similarly open sourced their code?

40 years of personal computers later, I’m satisfied with how the industry looks now, but curious as what might have been… if only Woz had known.

UPDATE: 3 days after posting, Bell Mensch of The Western Design Center answered the questions of my previous post on the never-built 65(24)02. Bill is not only one of the designers of the 6502, but he was one of the “defectors” from Motorola who worked on the 6800 too. That, and Bill’s company has sold billions of 6502s since the 1970s, including the W65C02 in the Apple IIc and W65C816S in the Apple IIgs. See that post for those answers.

Following-up on this post, apple2history.org has a detailed (but know doubt simplified) history of Apple as told from the perspective of the Apple II. TL;DR: Apple bet the company on the step-change Apple ///, thinking the II wouldn’t be popular for another year. Despite that lesson, they repeated that mistake again for the Lisa and Macintosh. Or in short, Apple didn’t put the time, effort, and money into the Apple II series despite it’s popularity for over a decade.

Given 40 years of hindsight, that was a mistake. Given 40 years of learnings in general about the computer industry, a better strategy for Apple would have been internally competing team working on annual releases of the Apple II, each with some incremental but significant upgrade. Obvious changes would be doubling the CPU speed to 2MHz then 4Mhz then 8Mhz, double sided floppies, higher resolution graphics, sound chips, math co-processors.

Along that path I’ve no doubt someone would have thought of 24 bit addresses, which would have let backward compatibility to the original Apple ][ be simplified to code and memory up to 64K, and new ROMs and new code addressing the flat addresses space above that limit. The requirement of backward compatibility was one factor that made updates to the Apple II so challenging, but mostly it was Apple’s push to step outside that legacy that left the company beyond vs. PCs and Windows, but that is another story and other lessons for another day.

UPDATE 2: Below is the advertisement for the Apple I, from 1976

UPDATE: One month later, I thought I was finished with story, but then stumbled on the Synertek page on Wikipedia. Turns out Apple didn’t buy 6502s from MOS, they bought them from Synertek.

And according to “Oral History of Robert “Bob” Schreiner” (Bob being the founder of Synertek), Steve Jobs did come calling a few years into Apple to ask for an upgraded 6502:

I got a call from Steve Jobs. And Steve called up and said, “Well, we like your product, we bought a lot of parts, but the time has come to go to a 16-bit machine. Are you going to design a 16-bit version of the 6500?” And I said, “No.” I said, “Would you be willing to fund it?” And he said, “No.” I said, “Well, let me tell you, to take on a project like that is absolutely betting the farm, and I can’t afford to do it, and I don’t think my board would let me do it. So the answer is no.” And he said, “Well, you have to understand that that means you’re forcing us to switch to the 68000.” I said, “Yeah, I knew that was going to happen someday, Steve, but there’s nothing I can do to prevent it. I don’t have the resources to build—design, build, and support a 16-bit machine. Even though you’re a great customer, give us lots of orders, I just can’t afford to take that gamble.”

Synertek soon was purchased by Honeywell. Between that and Apple’s move to the Motorola 68000 killed Synertek. If only Apple had said yes to paying for that design, Apple would have probably ended up being a chip maker, and we’d be on the A45 chip by now instead of the A12/M3.

By "Luni"


HardcoverThe Next StepThe Next StepThe Next StepThe Next Step The Next StepThe Next StepThe Next Step



Recent blog posts