Seyed Masoud Hosseini · Overview · Study log · Ideas · Transcript · RSS feed

Embedded Systems, 6502 breadboard computer · Lecture 26 of 29 · 36:52

Lecture 26: Running MSBASIC on My Breadboard 6502 Computer

Running MSBASIC on my breadboard 6502 computer on YouTube

Study guide

What this lecture covers

The lecture ports Microsoft BASIC for the 6502 to the breadboard computer built throughout this series, using the open-source MSBASIC repository that already targets several classic machines (Commodore, Apple II, and others) but not this one. It follows directly from the previous video's cc65-based BIOS and ROM-image work, and builds on the Wozmon port from earlier videos.

By the end, you can explain how to add a new hardware target to an existing multi-platform assembly codebase by working through the compiler's errors one at a time, how BASIC calls into hardware-specific I/O routines through fixed addresses, and how to debug both a wrong-address bug and a Ctrl-C handling bug using the tools already built.

Key ideas

  • Iterative build-and-fix workflow: rather than understanding the entire MSBASIC codebase up front, the lecture treats compiler errors as a to-do list, defining or adjusting one missing configuration value at a time until the build succeeds.
  • Conditional compilation per platform: the codebase selects platform-specific code and constants with preprocessor-style .ifdef blocks; adding a new computer means adding a new branch (eater) alongside the existing Commodore, Apple, and OSI definitions.
  • Zero-page layout: because zero-page memory access is faster on the 6502, BASIC reserves specific zero-page ranges for its variables; porting requires laying out non-overlapping start addresses (zp_start1 through zp_start4) that fit the target machine's available zero page, including room for the input buffer.
  • BIOS hooks as symbols, not hardcoded addresses: rather than manually looking up and typing in ROM addresses for character-in/character-out routines, the lecture adds matching labels directly in the BIOS source so the linker resolves them automatically and correctly.
  • Global label namespace conflicts: combining Wozmon and BASIC source in one build surfaces a duplicate label (run) that must be renamed, since the assembler shares one namespace across all included files.
  • Linker configuration mirrors the previous video's pattern: memory regions for zero page, ROM, Wozmon, and the reset vector are defined similarly to the earlier BIOS video, with BASIC's code now filling most of ROM.
  • Symbol/label file for locating entry points: the linker's generated label file lets you look up addresses like BASIC's cold_start label without hardcoding or guessing them.
  • Real bugs, real debugging: a broken Ctrl-C handler traces back to comparing the accumulator against the wrong operand form (a memory address instead of an immediate value), and doubled blank lines trace back to a mismatch between Wozmon's carriage-return-only output and BASIC's carriage-return-plus-linefeed output.

Walkthrough

The MSBASIC code (0:00)

The lecture introduces the Microsoft BASIC for 6502 repository, its make.sh build script that assembles and links nine existing hardware targets, and the plan to add a tenth target for this computer by working through the same assemble-and-link pipeline.

Creating our own version of MSBASIC (1:42)

A new eater branch is added to the platform-selection logic, initially copying the Commodore BASIC 2 configuration file as a starting point, then stripped down to bare minimum settings to discover what is actually required through trial and error with the build.

Zero-page configuration (4:53)

Build errors reveal overlapping zero-page variable regions inherited from the Commodore layout. The lecture works out non-overlapping start addresses for each zp_start block by counting bytes used by each group of variables, and leaves room in the zero page for BASIC's input buffer rather than placing it elsewhere in memory.

Configuring our version (9:32)

Further build errors point to undefined configuration constants (RAM start, terminal widths, stack space, and hooks for character I/O, control-C detection, and load/save). Each is filled in with a reasonable placeholder value or address, deferring correctness on some (like user, space_for_gosub) until they cause visible problems.

Adding our BIOS code and Wozmon (13:08)

The BIOS and Wozmon code from the previous video are pulled into the build via the project's extra.s include mechanism. A duplicate label conflict (run) between Wozmon and BASIC is resolved by renaming Wozmon's label.

Linker configuration (14:15)

A linker configuration file is built by adapting the Commodore version, defining memory regions for the zero page, ROM, the relocated Wozmon block, and the reset vector, following the pattern established in the previous BIOS video.

Pointing BASIC to our BIOS (18:50)

Rather than hardcoding potentially-wrong addresses for mon_c_out, mon_read_key, and related hooks, the lecture adds matching labels directly at the BIOS routines' definitions so the linker resolves the correct addresses automatically. Stub routines are added for load, save, and Ctrl-C detection so the build succeeds even though this computer has no file system yet.

Running BASIC! (23:09)

The image is written to an EEPROM using the mini-pro tool with an updated T48 programmer. After booting into Wozmon, the linker's generated label file is used to find BASIC's cold_start address, and jumping there starts BASIC successfully, confirmed by running a simple PRINT statement and a short FOR/NEXT loop program.

Bugfixes and making control-C work (26:32)

Two problems are addressed: doubled blank lines caused by a terminal setting interacting with BASIC's carriage-return-plus-linefeed output are fixed by making Wozmon itself emit both a carriage return and a line feed everywhere it currently emits only a carriage return; and a Ctrl-C handler is written from scratch by finding the platform-specific include point in BASIC's source and adding a routine that checks for a pressed key matching ASCII code 3.

Everything is working / Not everything is working / Everything is actually working now (32:30)

A convenience jump is added at the very start of ROM so BASIC can be launched from the easy-to-remember address $8000 instead of the harder-to-recall cold_start label. Testing reveals the new Ctrl-C handler doesn't actually stop a running program; the lecture finds the bug is comparing the accumulator against memory address 3 rather than the immediate value 3, fixes it, and confirms Ctrl-C now correctly interrupts a running BASIC program without losing it, unlike the earlier hardware-reset workaround.

Before you watch

  • The previous video's introduction to the cc65 toolchain, linker configuration, and BIOS structure.
  • The earlier videos on Wozmon and its adaptation to the serial interface.
  • Comfort with 6502 assembly, zero-page addressing, and reading build error messages.

Check your understanding

  1. Why does laying out zero-page variables require checking for overlap between different zp_start blocks?
  2. How does defining a matching label directly in the BIOS source avoid the need to hardcode a ROM address in the BASIC configuration?
  3. What caused the doubled blank lines, and why was the fix made in Wozmon rather than in BASIC?
  4. What was the actual bug in the first Ctrl-C implementation, and why did it fail silently instead of producing a build error?

Chapters

From the YouTube description

More 6502: https://eater.net/6502
Code from this video: https://github.com/beneater/msbasic

Support these videos on Patreon: https://www.patreon.com/beneater or https://eater.net/support for other ways to support.

------------------

Social media:
Website: https://www.eater.net
Twitter: https://x.com/beneater
Patreon: https://patreon.com/beneater
Reddit: https://www.reddit.com/r/beneater

Special thanks to these supporters for making this video possible:
19day, Adrien Friggeri, Aleksey Smolenchuk, Anthony Weems, anula, Ben, Ben Cochran, Benjamin D. Williams, Benjamin Elder, Benjamin Keil, Benji Bromberg, Bill Cooksey, Binh Tran, Богдан Федоров, Bradley Stach, Brian Haug, Burt Humburg, Carl Fooks, Carsten Schwender, Chad Fertig, Chai, Chris Anders, Chris Lajoie, criis, Cristi Cobzarenco, Daniel Tang, Daniel Zimmer, Dave Walter, Dave Westwood, David Clark, David Cox, David Dawkins, David House, David Klassen, David Sastre Medina, David Turner, Dean Winger, Deep Kalra, DemoniacDeath, Dennis Henderson, Dilip Gowda, Dirk Sperling, Dmitry Guyvoronsky, Dustin Campbell, Dzevad Trumic, Emilio Mendoza, Eric Dynowski, Erik Broeders, Erik Granlund, Ethan Sifferman, Eugene Bulkin, Evan Serrano, Evan Thayer, Eveli László, Florian Bürgi, fxshlein, George Harris, George Miroshnykov, ghostdunk, Glen Jarvis, Gregory Burns, GusGold, Hailey, Hovis Biddle, Ingo Eble, Ingram Leedy, Isaac Parker, Jack McKinney, Jacob Ford, James Capuder, James Will, Jason DeStefano, Jason Grim, Jason Thorpe, JavaXP, Jaxon Ketterman, jemmons, Jeremy Cole, Jesse Miller, Jim Kelly, Jim Kelly, Jim Knowler, Joe Beda, Joe Pregracke, Joe Rork, Joel, John Henning, Jon Dugan, Jonn Miller, Josh Smith, Justin Graziani, Justin Williams, Kai Wells, Kefen, Ken Paul, Kennard Smith, Kenneth Christensen, Kevin McQuown, Kristian Høy Horsberg, Kyle Kellogg, Lambda GPU Workstations, Larry Scherr, László Bácsi, Lithou, Marcos Fujisawa, Marcus Classon, Mariano Uvalle, Mark Day, Martin Noble, Mats Fredriksson, Matthew Clifford, melvin2001, Michael Cartwright, MICHAEL SLASS, Michael Tedder, Michael Timbrook, Michael Weitman, Miguel Ríos, Mike Coate, mikebad, Miles Macchiaroli, Muqeet Mujahid, Nate Welch, Nicholas Counts, Nicholas Moresco, Nick Chapman, Olivier HUBER, Örn Arnarson, Owen Arnett, Paul Heller, Paul Pluzhnikov, Pete Dietl, Phil Dennis, Philip Hofstetter, Ponytail Bob, ProgrammerDor, Ralph Irons, Randal Masutani, Randy True, raoulvp, real_huitz, Ric King, Richard Wagoner, Rick Hennigan, Rob Bruno, Robert Brown, Robert Diaz, Robey Pointer, Roland Munsil, Ryan Morrison, Sagnik Bhattacharya, Sam Sturgis, Scott Gorlick, Scott Holmes, Sean Patrick O’Brien, Sergey Kruk, snc, SonOfSofaman, sorek.uk, Spencer Ruport, Stefan Nesinger, Stephen Kovalcik, Stephen Riley, Steve Jones, Thomas Eriksen, Tim Oriol, Tim Sanders, Tim Walkowski, Tom, Tom Smith, Trevor Johnston, Trey Webb, tryonlinux, Tyler Latham, Vincent Bernat, Warren Miller, Wraithan McCarroll

0:00 The MSBASIC code
1:42 Creating our own version of MSBASIC
4:53 Zero-page configuration
9:32 Configuring our version
13:08 Adding our BIOS code and Wozmon
14:15 Linker configuration
18:50 Pointing BASIC to our BIOS
23:09 Running BASIC!
26:32 Bugfixes and making control-C work
32:30 Everything is working
34:16 Not everything is working
35:29 Everything is actually working now

← Lecture 25: A Simple BIOS for My Breadboard Computer · 27 of 29: How input buffering works →