# cbmbasic runs Commodore BASIC as a native script instead of an emulator

> cbmbasic is a portable implementation of the BASIC that shipped with the Commodore 64, and the thing that sets it apart is that it does not emulate the 6502 processor. It interprets BASIC directly and compiles to native code, which is roughly a thousand times faster than the real machine and lets a BASIC program run as a Unix script with a hashbang line.

**mist64/cbmbasic** — cbmbasic, a portable version of Commodore's version of Microsoft BASIC 6502 as found on the Commodore 64

- Repository: https://github.com/mist64/cbmbasic
- Stars: 521 · Forks: 80
- Language: C
- License: not declared
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/mist64-cbmbasic

## Compatible, and not an emulator

cbmbasic is a 100% compatible version of Commodore's version of Microsoft BASIC 6502 as found on the Commodore 64, and it can be used in interactive mode or with a BASIC file passed as a command line parameter.

The compatibility claim is the headline, and it is a strong one. Commodore BASIC V2 is a specific dialect with specific keywords, specific error messages and specific behaviour that differ from other BASICs of the era, and the promise is that a program written for the Commodore 64 runs unchanged here.

The implementation approach is stated immediately after, and it is the interesting part. This source does not emulate 6502 code; all code is completely native.

That distinction matters more than it might appear. An emulator runs the original machine's processor, which means you get the original behaviour exactly, and you also get the original speed, along with the work of writing or reusing a 6502 interpreter. A native implementation parses and executes the BASIC source directly, so the behaviour is reproduced without reproducing the hardware.

The result is that cbmbasic is a BASIC interpreter written in C that behaves like a Commodore 64, rather than a Commodore 64 that happens to be written in C. The library layout in the repository confirms this: the interpreter core is cbmbasic.c, the operating system interface is runtime.c, the console handling is console.c, and the plugin system is plugin.c.

The name in the repository title says it plainly: cbmbasic, Commodore BASIC V2 as a scripting language. That framing is the whole project in six words. It is not primarily an emulator, and the interesting use is not running old games but running old BASIC programs, and writing new ones, on a modern machine.

The project is C, with the default branch master and the last push on 2026-04-03. The licence is listed as unknown, though the documentation describes it in its own terms rather than naming a standard licence.

## The speed figure, and what it means in practice

The performance claim is given as a single sentence. On a 1 GHz CPU you get about 1000x speed compared to a 1 MHz 6502.

The two figures are the clock speeds and the ratio is the point. A real Commodore 64 runs at roughly 1 MHz, so the same program on a 1 GHz machine runs in about a thousandth of the time.

That number is a reasonable way to express the difference between interpreting a language and emulating a processor, and it has a practical consequence that is easy to miss. The original Commodore 64 was fast enough that a BASIC program doing real work was genuinely slow. A loop that counts to a million takes a noticeable fraction of a minute. On a native implementation the same loop is over before you notice it, which means you can write programs that would have been impractical on the original machine and still run them here.

The performance also changes what the interpreter can be used for. A Commodore BASIC program that had to be run on the real hardware can now be part of a build, a test or a pipeline, and the runtime being negligible is what makes that plausible.

The compatibility list is the other thing the documentation is careful about. It has been tested with Mac OS X 10.4 and 10.5 on i386, x86_64 and ppc with GCC 3.3 and 4.0, with Debian Linux Etch with GCC 3.3 and 4.1, and with Windows NT using Visual Studio 2005 and 2008. Other CPUs, operating systems and compilers should work, too.

The word tested is doing the work there, and the list shows its age. These are configurations from the middle of the 2000s, which tells you the portability claim was made when the project was written and the list has not been refreshed since. The expectation that other platforms work is reasonable for a few thousand lines of C with a small operating system interface, but it is an expectation rather than a tested fact.

There is one platform-specific note. Windows users should also install the Microsoft Visual C++ 2005 SP1 Redistributable Package for x86, which is the runtime the Windows build was linked against.

## Three ways to run it, and the one that is unusual

The usage section describes three modes, and the third is the one that makes this more than a BASIC interpreter.

You can use cbmbasic in interactive mode by just running the binary without parameters, which is the Commodore 64 experience: a prompt, a line of input, an immediate answer.

You can specify an ASCII-encoded BASIC program on the command line, which is the batch mode.

And you can use cbmbasic as a UNIX scripting language by adding a hashbang line to your BASIC program and making it executable. The example is:

```
    $ ls -l hello.bas 
    -rwxr-xr-x  1 mist  staff  40  7 Apr 21:30 hello.bas
    $ cat hello.bas 
    #!/usr/bin/env cbmbasic
    PRINT"HELLO WORLD!"
    $ ./hello.bas 
    HELLO WORLD!
```

The hashbang line names the interpreter, the file is marked executable, and the program runs as an ordinary command. The listing shows the file with the execute permission set and the forty byte size of a two-line file.

That last mode is the interesting one. A Commodore BASIC program becomes a Unix script that any tool can invoke, that composes with shell pipelines, and that you can put in a cron job. The language is 1980s Commodore BASIC and the integration model is a Unix shebang, and the combination is unusual in a good way.

The interpreter reads the file, so the syntax is the Commodore one and there is nothing Unix-specific about the program body. That means you can take an existing Commodore BASIC program, add one line at the top, and run it somewhere it could never have run before.

The example program itself is the shortest possible demonstration. A PRINT statement with the string in quotes and no spaces around the parenthesis, which is the Commodore style, and it prints HELLO WORLD! with the exclamation mark, exactly as a Commodore 64 would.

## The plugin system and the extras it adds

cbmbasic implements a small plugin system that lets developers add additional statements, functions and so on, and it is switched on with a statement rather than a command line flag.

You turn it on with SYS 1 and turn it off with SYS 0. The mechanism is period-appropriate and rather neat: SYS is a Commodore BASIC statement that calls into the operating system, so using it to toggle an extension mechanism is exactly the idiom a Commodore programmer would expect.

The additional statements are three. LOCATE with y and x sets the cursor position. SYSTEM with a string runs a command line command. And there is an extended WAIT with port and mask, which implements the Bill Gates easter egg.

That last one is the famous bug in the original Commodore KERNAL, where a WAIT on a particular address would copy the contents of memory to a screen address, which is the mechanism behind the famous trick of displaying anything on a Commodore screen without touching the operating system normally. It is a historical curiosity rather than a feature, and implementing it is a commitment to compatibility rather than an attempt to build something useful.

The two functional additions are more interesting. SYSTEM is the one that makes the interpreter scriptable in the other direction, since it lets a BASIC program run a shell command and continue. And LOCATE gives the interpreter cursor control, which is what you need to write a text-mode program that positions the cursor rather than just scrolling.

Both of those are extensions rather than Commodore behaviours, so they are gated behind the plugin switch. The default is off, which means a program that relies on them fails in a way that is obvious, and turning them on is a deliberate act in the source.

The plugin system is also the extension point for the project itself, since it is how new statements and functions get added without modifying the interpreter core.

## The internals, and what is still missing

The internals section is short and it explains the architecture in two paragraphs, which is the most valuable thing in the documentation.

The core of the BASIC interpreter is in the file cbmbasic.c, which is platform, endianness and bitness independent. For all I/O, it calls out into runtime.c, so it should be possible to adapt this project for any operating system by just changing runtime.c.

That is a clean separation and it is the design you would choose for a portable interpreter. The parsing, the evaluation and the statement dispatch stay identical everywhere, and everything that touches the outside world lives in one file. Porting to a new operating system means writing one file rather than auditing the interpreter for platform assumptions.

The second paragraph explains the dispatch mechanism. All function calls that the core interpreter cannot handle end up in kernal_dispatch() in runtime.c, where a switch statement dispatches these to C functions.

The name is the giveaway, and it is a good one. The Commodore machine had a KERNAL ROM with routines for character input, character output, screen handling, file operations and timing, and a Commodore BASIC program called into them. So this project reimplements the KERNAL as a set of C functions, and the interpreter calls them through a single switch.

For Commodore BASIC, runtime.c has to support several Commodore KERNAL library routines. Some of them are very important, such as CHRIN and CHROUT, which are the character input and character output calls that almost every program uses indirectly. And some are only used for certain BASIC statements, such as LOAD, SAVE, OPEN and SETTIM, which are the file and timer operations.

And then the honest sentence: runtime.c does not implement all functions yet.

That is the single most important limitation in the project, and it is stated in the documentation rather than hidden. A program that uses a statement backed by an unimplemented routine will fail, and the set of statements affected is exactly the file and timer operations. So the interpreter covers the language well and covers the file system incompletely, which is a sensible place to stop if the goal is running programs rather than managing data.

The repository layout matches the description: cbmbasic.c, runtime.c, plugin.c, console.c and glue.h, with readdir.c and readdir.h providing directory listing, a local stat.h, a Visual Studio project file, makefiles for Unix, Sun 32-bit and Windows, a test/ directory and an ANSI_Extension.md document.

## Building it, and the licence

The build is a small makefile, and it is worth reading because it shows how small the project is.

```make
OBJS=cbmbasic.o runtime.o plugin.o console.o
CFLAGS+=-Wall -O3

all: cbmbasic

cbmbasic: $(OBJS)
	$(CC) $(LDFLAGS) -o cbmbasic $(OBJS)

clean:
	rm -f $(OBJS) cbmbasic
```

Four object files, cbmbasic, runtime, plugin and console, compiled with warnings on and optimisation at level three, linked into a single binary called cbmbasic. And a clean target that removes the objects and the binary.

The single-binary result is the point. There is no library to install and nothing to configure, so using cbmbasic is cloning the repository, running make, and running the binary. For a project whose whole purpose is to be a portable tool that drops into a Unix environment, that is the right shape.

The three makefiles at the repository root are for Unix, for Sun 32-bit and for Windows, and there is a Visual Studio project file for the Windows build. The presence of a Sun 32-bit makefile is a period marker, since that was a meaningful target for a Unix workstation in the era the project was written.

The licence is unusual and worth reading in full. It says: feel free to use this project for any purpose, give credit if you like, and send back improvements to the authors, if you like, so that others can benefit from it, and to see the source for licence details.

That is not a standard licence and it is not a legal grant in the usual sense. It is a request, and it tells you something about the project: the authors wrote it, they want it used, and they would rather have improvements sent back than forked away. The GitHub metadata lists the licence as unknown because there is no standard identifier to record.

The two contacts are Michael Steil and James Abbatiello. Steil is well known in the Commodore community for his work on the C64 and related systems, and the repository's recent activity, with the last push in April 2026, suggests it is still maintained rather than abandoned.

So the practical summary is that this is a small, portable, well-understood interpreter for a specific and much-loved dialect of BASIC, with a scripting integration that is genuinely useful, a compatibility promise that is the main selling point and a known gap in the file-handling routines that you should check against the programs you want to run.

## Conclusion

Adopt cbmbasic if you want to run Commodore BASIC programs on a modern machine, or to write small scripts in a familiar dialect, since the interpreter is native and fast. Skip it if you need the full Commodore BASIC environment, because the documentation says the runtime does not implement all the functions yet. Verify first which KERNAL routines your program depends on, since some statements are still missing, and that the platform you are on is one the build covers, since there are separate makefiles for Unix, Sun and Windows.

## FAQ

### What is cbmbasic and does it emulate the Commodore 64?

It is a 100% compatible version of Commodore's version of Microsoft BASIC 6502 as found on the Commodore 64, written in C. It does not emulate 6502 code at all; all the code is completely native, which is why on a 1 GHz CPU it runs about 1000 times faster than a 1 MHz 6502. You can use it interactively, pass a BASIC file on the command line, or run it as a Unix script.

### How do I run a Commodore BASIC program as a Unix script?

Add a hashbang line to the top of the BASIC program and make the file executable, for example a first line of `#!/usr/bin/env cbmbasic` followed by a PRINT statement. Then running the file directly executes it, and it composes with shell pipelines and cron like any other script. The example in the documentation is a forty byte hello.bas file that prints HELLO WORLD!

### What does the cbmbasic plugin system add, and what is not implemented?

The plugin system is switched on with the statement SYS 1 and off with SYS 0, and it adds the LOCATE statement to set the cursor position, the SYSTEM statement to run a command line command, and an extended WAIT with port and mask that implements the Bill Gates easter egg. Separately, the documentation notes that runtime.c does not implement all functions yet, which affects the Commodore KERNAL routines behind statements such as LOAD, SAVE, OPEN and SETTIM.

## Sources

- [Issues](https://github.com/mist64/cbmbasic/issues)
- [mist64/cbmbasic on GitHub](https://github.com/mist64/cbmbasic)
- [README](https://github.com/mist64/cbmbasic/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/mist64-cbmbasic
