# Yes, Microsoft 6502 BASIC was clearly a port of their 8080 BASIC.

Unfortunately the original 8080 source code for Microsoft BASIC [isn't
easily available][11838], so we can't compare it directly to that
without going to the Harvard University library to read the paper
copy.

But the Microsoft source code for a later version of their 8080 BASIC,
BASIC-80 5.2 (actually marked 5.11 in the source) is [available
online][5.2]. This is copyright 1982 (from the copyright notice in
`INIT.MAC`), but contains material obviously from the original 8080
source code, such as the following comment in `BINTRP.MAC`:

    ;--------- ---- -- ---- ----- --- ---- -----
    ;COPYRIGHT 1975 BY BILL GATES AND PAUL ALLEN
    ;--------- ---- -- ---- ----- --- ---- -----
    ;
    ;ORIGINALLY WRITTEN ON THE PDP-10 FROM
    ;FEBRUARY 9 TO  APRIL 9 1975

Comparing this with the [6502 source code][6502] we see substantial
similarities in the overall organization of the code and almost exact
correspondence of many routines within it.

### START and INIT

For example, the entry point in both versions is at address 0 and
contains `JMP INIT`; in both cases the `INIT` routine overwrites the
target of this `JMP` with the address of a routine called `READY` that
does a "warm start". After that there are a couple of words storing
the addresses of routines to convert a floating point number to an
integer and vice versa.

Here's the 8080 version from 1982:

            PUBLIC  START
    START:
            PUBLIC  JMPINI
    JMPINI: JMP     INIT                    ;INIT IS THE INTIALIZATION ROUTINE
                                            ;IT SETS UP CERTAIN
                                            ;LOCATIONS DELETES FUNCTIONS IF
                                            ;DESIRED AND
                                            ;CHANGES THIS TO JMP READY
                                            ;WARM START FOR ISIS

                                            ;OF THE ROUTINE TO CONVERT [A,B]
                                            ;TO A FLOATING POINT NUMBER IN THE FAC
            DW      FRCINT                  ;TURN FAC INTO AN INTEGER IN [H,L]
            DW      MAKINT                  ;TURN [H,L] INTO A VALUE IN THE FAC
                                            ;SET VALTYP FOR INTEGER

And the 6502 version from 1978:

    START:  JMP     INIT            ;INITIALIZE - SETUP CERTAIN LOCATIONS
                                    ;AND DELETE FUNCTIONS IF NOT NEEDED,
                                    ;AND CHANGE THIS TO "JMP READY"
                                    ;IN CASE USER RESTARTS AT LOC ZERO.
    RDYJSR: JMP     INIT            ;CHANGED TO "JMP STROUT" BY "INIT"
                                    ;TO HANDLE ERRORS.
    ADRAYI: ADR(AYINT)              ;STORE HERE THE ADDR OF THE
                                    ;ROUTINE TO TURN THE FAC INTO A 
                                    ;TWO BYTE SIGNED INTEGER IN [Y,A]
    ADRGAY: ADR(GIVAYF)>            ;STORE HERE THE ADDR OF THE
                                    ;ROUTINE TO CONVERT [Y,A] TO A FLOATING
                                    ;POINT NUMBER IN THE FAC.

### STROUT

Another example is the `STROUT` routine, which clearly works in the
same way, modulo the differences in processor architecture, and even
has some comments that are nearly identical. Here's the 8080 version:

    ;
    ; PRINT THE STRING POINTED TO BY [H,L] WHICH ENDS WITH A ZERO
    ; IF THE STRING IS BELOW DSCTMP IT WILL BE COPIED INTO STRING SPACE
    ;
    STROUI: INX     H                       ;POINT AT NEXT CHARACTER
    STROUT: CALL    STRLIT                  ;GET A STRING LITERAL
    ;
    ; PRINT THE STRING WHOSE DESCRIPTOR IS POINTED TO BY FACLO.
    ;
    STRPRT: CALL    FREFAC                  ;RETURN TEMP POINTER BY FACLO
            CALL    GETBCD                  ;[D]=LENGTH [B,C]=POINTER AT DATA
            INR     D                       ;INCREMENT AND DECREMENT EARLY
                                            ;TO CHECK FOR NULL STRING
    STRPR2: DCR     D                       ;DECREMENT THE LENGTH
            RZ                              ;ALL DONE
            LDAX    B                       ;GET CHARACTER TO PRINT
            CALL    OUTDO
            CPI     13
            CZ      CRFIN
            INX     B                       ;POINT TO THE NEXT CHARACTER
            JMP     STRPR2                  ;AND PRINT IT...
            PAGE

And here's the 6502 version:

    ;
    ; PRINT THE STRING POINTED TO BY [Y,A] WHICH ENDS WITH A ZERO.
    ; IF THE STRING IS BELOW DSCTMP IT WILL BE COPIED INTO STRING SPACE.
    ;
    STROUT: JSR     STRLIT          ;GET A STRING LITERAL.
    ;
    ; PRINT THE STRING WHOSE DESCRIPTOR IS POINTED TO BY FACMO.
    ;
    STRPRT: JSR     FREFAC          ;RETURN TEMP POINTER.
            TAX                     ;PUT COUNT INTO COUNTER.
            LDYI    0
            INX                     ;MOVE ONE AHEAD.
    STRPR2: DEX
            BEQ     PRTRTS          ;ALL DONE.
            LDADY   INDEX           ;PNTR TO ACT STRNG SET BY FREFAC.
            JSR     OUTDO
            INY
            CMPI    13
            BNE     STRPR2
            JSR     CRFIN           ;TYPE REST OF CARRIAGE RETURN.
            JMP     STRPR2          ;AND ON AND ON.

### PTRGET

Even routines that are different due to feature changes are pretty
clearly derived from common original source. For example, the `PTRGET`
routine that that reads a variable name and fetches its value uses a
pair of zero-page memory locations in the 6502 version to store the
variable name, which is limited to two characters in that older
version of BASIC. The newer 8080 code allows up to 40 characters in a
variable name, but still stores the first two characters of the name
in the C and B registers (memory was used in the 6502 because it has
far fewer registers) and compares those first, only moving on to a
further comparison with the rest of the name in a memory buffer if
that fails.

And of course there's the similarity in the comments and routine name
itself. The 8080 version:

    ; ROUTINE TO READ THE VARIABLE NAME AT THE CURRENT TEXT POSITION
    ; AND PUT A POINTER TO ITS VALUE IN [D,E]. [H,L] IS UPDATED
    ; TO POINT TO THE CHARACTER AFTER THE VARIABLE NAME.
    ; VALTYP IS SETUP. NOTE THAT EVALUATING SUBSCRIPTS IN
    ; A VARIABLE NAME CAN CAUSE RECURSIVE CALLS TO PTRGET SO AT
    ; THAT POINT ALL VALUES MUST BE STORED ON THE STACK.
    ; ON RETURN, [A] DOES NOT REFLECT THE VALUE OF THE TERMINATING CHARACTER
    ;
    PTRGET: XRA     A                       ;MAKE [A]=0

And the 6502 version:

    ; ROUTINE TO READ THE VARIABLE NAME AT THE CURRENT TEXT POSITION
    ; AND  PUT A POINTER TO ITS VALUE IN VARPNT. [TXTPTR]
    ; POINTS TO THE TERMINATING CHARCTER.. NOT THAT EVALUATING SUBSCRIPTS
    ; IN A VARIABLE NAME CAN CAUSE RECURSIVE CALLS TO "PTRGET" SO AT
    ; THAT POINT ALL VALUES MUST BE STORED ON THE STACK.
    ;
    PTRGET: LDXI    0               ;MAKE [ACCX]=0.

### Comparison with Other Object Code

Though we don't have original source for an 8080 version of Microsoft
BASIC from the same era as the 6502 source, we do have binaries that
can be disassembled. Comparing [this disassembly of Altair
BASIC 3.2][altair] we can also find substantial similarities in the
code (including all the routines mentioned above), though of course
there are no comments to compare.

I myself have been working on a [disassembly of the 6800 BASIC][6800]
that Microsoft wrote for the Altair 680B after they'd written the 8080
basic for Altair's 8800 but probably before they started the 6502
version. Both ports were done by Ric Weiland, and again the 6800
version shows the same substantial similarities in code organization
and the details of how the particular routines work.



[11838]: https://retrocomputing.stackexchange.com/q/11838/7208
[5.2]: https://winworldpc.com/download/c2bfc380-c2b2-c2b4-7d00-11c3a7c29d25
[6502]: https://www.pagetable.com/docs/M6502.MAC.txt
[altair]: http://altairbasic.org/
[6800]: https://github.com/0cjs/altair-680-basic