Commodore, Microsoft, and the BASIC garbage collector

When Microsoft open sourced the 6502 BASIC source last September, one sentence in the announcement caught my attention and then would not let go of it. I went looking for what was behind that sentence, ended up in the source code, and finally asked the one person who would know: former Commodore engineer John Feagans, who was initially hired by Chuck Peddle to finish the PET project. John answered a whole slew of questions I had on this topic and he was kind enough to give me permission to share what he told me. There’s nothing Earth-shattering here, but it’s a lot of tiny details that haven’t been disclosed before.

What initiated my conversation with John Feagans

On September 3, 2025, Microsoft released the source for BASIC-M6502 on GitHub under the MIT license:

github.com/microsoft/BASIC-M6502

In the accompanying announcement, Microsoft states that the released version 1.1 contains fixes to the garbage collector identified by Commodore and implemented jointly in 1978 by Commodore engineer John Feagans and Bill Gates, on a trip Feagans made to Microsoft’s Bellevue offices, and that this is the version that shipped as the PET’s BASIC V2:

Bringing BASIC back: Microsoft’s 6502 BASIC is now Open Source

As far as I can find, that is the entire published record. Every article that covered the release quotes or paraphrases it. It does not say what the problem was, or what changed.

What the source shows

The released file carries a ChangeLog at the top. Two entries are dated July 1, 1978:

FIXED BUG WHERE REPLACING A LINE OVERFLOWING MEMORY LEFT LINKS
IN A BAD STATE. (CODE AT NODEL AND FINI) BUG#4

FIXED BUG WHERE GARBAGE COLLECTION NEVER(!) COLLECTS TEMPS
(STY GRBPNT  AT FNDVAR, LDA GRBPNT ORA GRBPNT+1 AT GRBPAS)
THIS WAS COMMODORE BUG #2

Those are the only two numbered bugs in the entire source listing. Everything else Microsoft logged is prose with no number attached. Somebody at Commodore was keeping a numbered list, and Microsoft was tracking against it.

The garbage collection fix (Commodore Bug #2) itself is simple. It makes the collector clear both bytes of a pointer instead of only the high byte, so that strings held only by a temporary descriptor stop being skipped. You can find it in your own C64. The BASIC V2 garbage collector routine at $B526 begins:

B526  A6 37     LDX $37
B528  A5 38     LDA $38
B52A  86 33     STX $33
B52C  85 34     STA $34
B52E  A0 00     LDY #$00
B530  84 4F     STY $4F
B532  84 4E     STY $4E

Both bytes cleared. That is Commodore bug #2, fixed.

Here is the added instruction in Microsoft’s source. The comment is theirs.

  FNDVAR: STX     FRETOP
          STA     FRETOP+1
          LDYI    0
          STY     GRBPNT+1
          STY     GRBPNT          ;BOTH BYTES SET TO ZERO (FIX BUG)

Every version of Microsoft BASIC for 6502 that predates the July 1978 fix has this bug, including the PET’s original 1977 BASIC and the KIM-1’s. All of them clear only the high byte and test only the high byte. GRBPNT holds the address of the descriptor belonging to the highest string found so far. When that descriptor is one of the temporaries, it sits in zero page, so the address has a zero high byte, and a test that looks only at the high byte reads it as “nothing found.” That is what Microsoft means by garbage collection never collecting temps.

The part that was not a bug

So this was an actual bug, and Commodore filed it as one. But on top of this, the garbage collector was terribly slow, and that wasn’t a bug, but an overall design problem that still exists in the version of Microsoft’s released source code on GitHub.

What Microsoft’s released source does not contain is any linked list or back pointer scheme. Its garbage collector is exactly the design the C64 has: reset the top of string space, scan the temporary descriptors, then every scalar variable, then every string array element, move the single highest live string, and then start the entire scan over again. One complete pass over every descriptor in memory for each string relocated.

BASIC v2 in the Commodore 64 still has the slow garbage collector routine found in the released Microsoft sources.

What John Feagans revealed during our conversation

I sent John the change shown above and asked whether that was the bug from his Bellevue trip. His answer sent me in a different direction.

The problem with garbage collection on the PET which I solved was the linear search of memory to see if anybody pointed at it. Then compacting one chunk at a time. I implemented a doubly linked list. It was one of two algorithms that Bill and I discussed that day in Bellevue, Wa.

It was embarrassing how the PET would go to sleep for minutes while the garbage collect was happening.

John described the cause of the slow garbage collection routine exactly, without being shown the code, almost 50 years after the fact. The linear search and the compacting of one chunk at a time is exactly what the original routine does and it’s why it’s so slow.

On the trip to Bellevue, Washington where John met with Bill Gates:

As an aside, Bill had just gotten his Purple Porsche and we went out to Shakeys Pizza for lunch.

We paid Bill $500 on a purchase order for his consulting time!

John’s response on how the slow garbage collection routine was actually fixed:

I implemented the code back in Santa Clara using the MDT editor and assembler. I transferred the code back to Bill via modem on the Silent 700 terminal. He put the code back into the macro assembler you see in the listing.

Were the back links added to Commodore BASIC 4.0?

Yes, and there was a version 3 which contained the code for the garbage collection, but we delayed for 4 and the other features.

And on the numbered bug list, which is something I had never seen described anywhere:

I compiled the lists of known bugs and they were sent by Telex to Microsoft. Object code and source files went at 300 baud on acoustic coupled phone lines. Error correcting protocols had not been developed for transmission so some items had to be sent multiple times and compared. The hex ascii object file format had checksums but not over the whole.

Finally, on who John was working with at Microsoft:

Ric Weiland was the primary developer of 6502 BASIC and my first contact. When he left Microsoft, I did all work with Bill.

There is support for that in the source. Buried in the startup code is an easter egg:

AUTTXT: ACRLF
        12
        DT"WRITTEN "
        DT"BY WEILAND & GATES"

Microsoft BASIC running on a KIM-1

Type A at the MEMORY SIZE prompt and BASIC prints the authors’ names, with Weiland’s first. It is reachable on a KIM-1, which I demonstrated in a YouTube video. It is not reachable on later Commodore machines, because the entire MEMORY SIZE block is conditionally assembled out when the source is built for Commodore.

What it adds up to

There were two separate pieces of Commodore garbage collector work in 1978, and it appears that Microsoft’s announcement conflated them.

The first is bug #2, the small correctness fix shown above. It carries a Commodore bug number, and John Feagans is the one who compiled Commodore’s numbered bug lists and sent them to Microsoft by Telex. So that fix almost certainly traveled the route he described: found at Commodore, written up by John, transmitted north, and fixed by Microsoft on July 1, 1978. It is in the released 1.1 source and it is in your C64’s BASIC v2.

The second is the speed problem. That is the one John and Bill Gates discussed at Bellevue, and John implemented it afterward, back in Santa Clara, as a doubly linked list. It was ready for a BASIC version 3 that Commodore held back and folded into BASIC 4.0.

Microsoft’s announcement describes the garbage collector fixes as jointly implemented by Feagans and Gates on the Bellevue trip. If the sequence above is right, that one sentence has merged two different things: a bug Commodore reported by Telex and Microsoft fixed, and an algorithm discussed at the Bellevue meeting between John Feagans and Bill Gates, then implemented back at Commodore. Neither one is quite what the sentence says.

So the Commodore 64, shipping in 1982, has the fix for “Commodore Bug #2”, and not the fix for the slow garbage collection, despite the fact that John Feagans implemented a faster garbage collection algorithm four years earlier.

One thing I cannot reconcile

John says the linked list code (faster garbage collection) went back to Microsoft and into the macro assembler listing. The listing Microsoft released is version 1.1, and its most recent ChangeLog entry is July 27, 1978. John’s fix is not in this version of the source code. So either the code went into a later Microsoft revision that has not been released, or the sequence is slightly different from how it is remembered after 48 years.

A postscript: the MICROSOFT! easter egg

I sent John the published article and asked him to check it for accuracy. He said it sounded like a true representation of how the code evolved, and then added this:

I was not involved when Bob Russell made a copy of my 8″ floppy disk with the source for 2.0. He should have used the 3.0 which already had the wait 6502,x code removed. When Bill stopped by the Commodore suite at CES he typed on a 4032 and was disappointed when the machine hung. :^)

The “wait 6502,x code” is the MICROSOFT! easter egg. In an early version of BASIC Microsoft provided to Commodore, WAIT 6502,n printed MICROSOFT! on the screen.

By the time of that CES it was gone, but WAIT itself still worked, so typing it on a 4032 did not print anything and did not crash. The machine sat in the wait loop forever, waiting on a condition that could never be met, because there is nothing at address 6502.

Leonard Tramiel described this in 2022, in a post called If Looks Could Kill. He was the one running the demo. His account adds that Gates arrived leading a group with a Japanese translator, that Leonard quietly warned him there was nothing at that address, and that he got a memorable look in return before smoothing it over for the crowd. He also explains how the egg was found in the first place: Microsoft supplied Commodore with a fanfold listing in which the code was hidden behind a NOLIST directive, and it only came to light when the object code was disassembled.

Corrections and additions are welcome. My thanks to John Feagans for his time, and for permission to publish this.

Sources

You may also like...

Leave a Reply

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