Mark Wharton Moonbase, 1985–1995

Microsoft's 6502 BASIC

Bill Gates and Ric Weiland completed Microsoft's BASIC for the 6502 in 1976. This is its version 1.1, of 1978, from the source Microsoft released under the MIT licence in 2025: your browser assembles that source and runs it on a 6502, as five of the machines it was built for.

How it works

This is Microsoft's own BASIC: the 1978 source, exactly as Microsoft released it (m6502.asm, under the MIT licence). It was written in DEC's MACRO-10, on a PDP-10 mainframe, and the source still builds for "PDP-10 SIMULATING 6502", as Microsoft ran it before any 6502 was at hand: try the PDP-10 above, and its DDT. When you open this page, your browser assembles that source into about 8K of 6502 machine code and runs it on Moonbase's own 6502, simulated in your browser, drawn beside the screen and lit by every instruction. The keys, the screens in Moonbase's own characters, and SAVE and LOAD come from this site, standing in for each machine's own ROM. And hidden in the code are its authors' signatures: type WAIT 6502,1 on the PET, or A at MEMORY SIZE? on the Apple.

TITLE   BASIC M6502 8K VER 1.1 BY MICRO-SOFTSEARCH  M6502SALLRADIX 10                        ;THROUGHOUT ALL BUT MATH-PAK. $Z::                            ;STARTING POINT FOR M6502 SIMULATOR        ORG     0               ;START OFF AT LOCATION ZERO.SUBTTL  SWITCHES,MACROS. REALIO=4                        ;5=STM                                ;4=APPLE.                                ;3=COMMODORE.                                ;2=OSI                                ;1=MOS TECH,KIM                                ;0=PDP-10 SIMULATING 6502…
Lines 1 to 15 of Microsoft's source: its title, and one number that chooses the machine BASIC is built for, 0 a PDP-10 standing in for a 6502. This page builds it five times, as 4, 3, 2, 1, 0.

How BASIC keeps a program

When you type a line with a number in front and press Return, BASIC keeps it in memory as bytes. Each keyword, such as PRINT or GOTO, becomes a single byte, a token, so the program takes less room and runs quicker. Everything else is kept as you typed it, a byte for each character.

Each line starts with two bytes that point to where the next line starts, then two bytes for its line number, and ends with a 0. Two bytes make one number with the low byte first: $0F $04 is $040F. To find a line, for a GOTO, BASIC follows these from the first line until it reaches the number. A pointer of 0 ends the program. LIST turns the tokens back into words as it prints them, and SAVE writes these same bytes, so a saved program is smaller than the text you typed. (Numbers starting with $ are in hex: see Bits and bytes.)

Type a line or two, and see the bytes Commodore's build keeps:

Its functions

BASIC's functions, in the order of its table of their addresses (and FN, those a program makes for itself with DEF FN). The arithmetic is Microsoft's own, in 6502: add, subtract, multiply and divide, and the rest made of those, on numbers of five bytes. One flag, KIMROM, set only for a KIM-1 with BASIC in its ROM, leaves COS, SIN, TAN and ATN out.

SGN(X)
−1, 0 or 1, by X's sign
INT(X)
the whole number at or below X
ABS(X)
X without its sign
USR(X)
a routine of the program's own, in machine code, at the address it has set, X handed to it
FRE(X)
the bytes free between the variables and the strings, the strings tidied up first; X is not used (FRE(0)), and more than 32,767 shows as negative
POS(X)
the column the next character will print in; X is not used
SQR(X)
the square root: X to the power ½, by LOG and EXP
RND(X)
a random number between 0 and 1: for X above 0, the next, made from the last by multiplying by one constant, adding another and swapping its bytes about; for X of 0, Commodore's build reads its timers and the others give the last again; for X below 0, a new sequence, started from X
LOG(X)
the natural logarithm: X split into a power of 2 and a fraction, a polynomial on the fraction, times LN(2)
EXP(X)
e to the X: as 2 to a power, the whole part straight into the exponent, a polynomial for the fraction
COS(X)
SIN(X + π/2)
SIN(X)
X divided by 2π, its fraction folded into a quarter turn, then a polynomial of six constants
TAN(X)
SIN(X) divided by COS(X)
ATN(X)
the angle whose tangent is X: made positive and less than 1, then a polynomial
PEEK(X)
the byte in memory at address X
LEN(X$)
the length of a string
STR$(X)
a number as a string, as PRINT would print it
VAL(X$)
a string read as a number
ASC(X$)
the code of a string's first character
CHR$(X)
the character with the code X
LEFT$(X$,N)
a string's first N characters
RIGHT$(X$,N)
its last N characters
MID$(X$,S,N)
N characters from the Sth; without N, the rest from the Sth

Each number is five bytes. The first is its exponent, the power of two with 128 added, 0 for the number 0; the other four are its mantissa, its digits in binary, the first bit kept for its sign. The fifth byte is the source's ADDPRC, "additional precision": with it BASIC keeps about nine digits, without it six.