dawnFORTH: Yet another crude Forth for the 65C02.
Posted: Mon Nov 24, 2025 9:04 am
IMPORTANT:
Please check Change History at the bottom of this post for the latest update!
---
Hi, everybody.
I'm new here to this forum. I share your love for old 8 bit CPUs and hope to contribute something worthwhile.
I am a retired computer service technician. Nothing glamorous, but it payed the bills. I started with electronics in the mid 70's and my lifelong obsession with computers was kindled in the late seventies when I programmed some punch cards for some mini-computer at my town's university (probably a PDP-8). I owned a lot of different computers in the 80's (and got myself quite in debt, which my dad had to bail me out of). I learned the usual programming language suspects: Basic, Pascal, C, but also 6502, 8080/Z80 and 8086 assembler. I always loved messing around in assembler, as it feels so much closer to the bare metal than any other programming language (C maybe an exception).
But when the 90's came and went, I pretty much stopped programming at home and used the computer more or less exclusively for gaming (another obsession which had started, of course, in the 80's). I only programmed "professionally" for about two to three years in my career. Other than that I was just another computer gamer (I never played on consoles. I don't like controllers).
Fast forward to last year. I was already semi-retired and had too much time on my hands when I stumbled over Ben Eater's channel on Youtube. I binge-watched all of his videos and my interest in programming the 6502 bare metal was re-kindled! After watching another video on Aaron Lanterman's channel, where his student had programmed a Forth interpreter/compiler on one of those WDC 65xx boards, I started thinking: "If this guy can do it, why can't I?".
I caved and ordered me a W65C02SXB board from Mouser.
I started to dig in and learned how to get this thing going. And, me massively overestimating my skill level, I started hacking away at that Forth interpreter/compiler that I had only a very vague idea of on what it was even supposed to be.
I only had very limited knowledge of compiler building. I had more or less zero knowledge of Forth.
And here is the result. This is the fourth iteration. It works. It's not complete. It's probably messy. It's not very optimized. Documentation might be lacking in places. But it works. It uses only two routines from the WDC monitor (character read and write), so it should be easily adaptable to any 65C02 computer out there. It's not going to work on the classic 6502 since I use some 65C02 exclusive commands (PHY and such).
I'm posting this here to get some reactions from you. Whether it's encouragement, constructive criticism or that you actually installed this thing somewhere and got it to work. Saying hi is also welcome.
I have no fancy Github page, so I will put future versions here in this thread.
I used a Mac mini M2 Pro as a cross development machine. I programmed dawnFORTH using the Vim/MacVim editor. The source was assembled using the vasm cross assembler. I wrote two little scripts to assist me with assembling and uploading the code to the board. The main uploading script was graciously provided to me by David Gray from WDC, he gave me his permission to upload it, so you can find at the bottom of this post.
Please let me know what you think. See you on the forums.
vasm webpage: http://sun.hasenbraten.de/vasm/
To make the correct vasm that works with my code I use:
The correct command line to create an object file that I can upload to my W65C02SXB board is:
To upload dawnFORTH into the ROM of my W65C02SXB board:
More detailed explanations are in the README.txt.
vim is part of macOS, but the GUI version MacVim is available here: https://macvim.org
Edit: I forgot to mention one "speciality" of dawnFORTH: It has variable CELL sizes. Default is two bytes, standard 16 bit integer. But you can blow it up to 16(!) bytes if you want to. No re-compile necessary. You can do that by writing the new cell size into CELL. Please let me know what you think of that.
Edit2: Another thing I forgot is that the line editor and EMIT are multibyte character capable. I'm German, so I need my äöüÄÖܧß...
Change History:
20251228-1359 CET+1
- Fixed... annoyance in "ACCEPT", where ACCEPT would use the input buffer pointer instead of a temporary one, leading to the input buffer pointer (thus SOURCE) being overwritten and subsequent input getting store into whatever buffer address you provided to ACCEPT.
- Fixed bug in "int_header" that would produce a random code address when called by ":NONAME".
- Fixed bug in "int_insertXT" that would produce an incorrect XT when paired with ":NONAME".
- Fixed bug in ">" that would produce incorrect flags with certain values.
- Fixed bug in "ALIGNED" that would incorrectly align an already aligned address, producing "a-addr CELL+".
- Changed "SAVE-INPUT" so it will compress multiple characters into one cell (depending on cell size).
- Added "NAME>STRING".
- Added "U/MOD" and "U/".
20251223-1217 CET+1
- SLITERAL now adds a zero-byte to the end of the string, so EVALUATE will work. This is not reflected in the length value and should be transparent to the user.
- EVALUATE now correctly saves the entire input specification and restores it on exit. Correctly passes the EVALUATE test suite on "forth-standard.org".
- Fixed "lean" to only delete comments. Thank you, Sam.
- Expanded and clarified README.txt.
20251221-2137 CET+1
- Bug fix. Fixed a bug where PARSE, PARSE-WORD would continue to read characters past the end of a string that wasn't zero-delimited.
20251221-0944 CET+1
- POINT UPGRADE. We're at version 0.6 now.
- Added the EXCEPTION word set.
- Realized that I was stupid and removed pushing HERE on the data stack from ALLOT and VARIABLE. Which resulted in a lot of hand wringing and rewriting of code all over the place.
- Optimized multiple functions in "stack.s" and "functions.s" and probably elsewhere.
- Removed "AHEAD", "int_resolveForward" and "int_resolveBackward" from the internal word set. They're now in "system.fth".
- Added "DP@", "DP!", "RP@" and "RP!" to the internal word set.
- Fixed several bugs (as usual).
20251206-1232 CET+1
- I added multi-byte capability to HOLD (and fixed a bug that resulted thereof).
- Added saving and restoring the data stack when using the (currently) one-level undo (accessed by pressing cursor-up on your ANSI terminal).
- Numerous small changes to stuff not worth mentioning.
20251126-0940 CET+1
- Uploaded the Python upload script graciously provided by and with permission of David Gray, WDC.
- Expanded README.txt to include the Python upload script.
- Added more CORE words in "system.fth".
20251125-1035 CET+1
- Worked on and expanded README.txt. Not finished, but has much more information now.
- Cleaned up dawnFORTH folder and resulting zip file. It's much smaller now. No changes to source code.
20251124-1802 CET+1
- Fixed problem where range testing the data stack pointer would corrupt processor flags. Division stopped working due to that.
Please check Change History at the bottom of this post for the latest update!
---
Hi, everybody.
I'm new here to this forum. I share your love for old 8 bit CPUs and hope to contribute something worthwhile.
I am a retired computer service technician. Nothing glamorous, but it payed the bills. I started with electronics in the mid 70's and my lifelong obsession with computers was kindled in the late seventies when I programmed some punch cards for some mini-computer at my town's university (probably a PDP-8). I owned a lot of different computers in the 80's (and got myself quite in debt, which my dad had to bail me out of). I learned the usual programming language suspects: Basic, Pascal, C, but also 6502, 8080/Z80 and 8086 assembler. I always loved messing around in assembler, as it feels so much closer to the bare metal than any other programming language (C maybe an exception).
But when the 90's came and went, I pretty much stopped programming at home and used the computer more or less exclusively for gaming (another obsession which had started, of course, in the 80's). I only programmed "professionally" for about two to three years in my career. Other than that I was just another computer gamer (I never played on consoles. I don't like controllers).
Fast forward to last year. I was already semi-retired and had too much time on my hands when I stumbled over Ben Eater's channel on Youtube. I binge-watched all of his videos and my interest in programming the 6502 bare metal was re-kindled! After watching another video on Aaron Lanterman's channel, where his student had programmed a Forth interpreter/compiler on one of those WDC 65xx boards, I started thinking: "If this guy can do it, why can't I?".
I caved and ordered me a W65C02SXB board from Mouser.
I started to dig in and learned how to get this thing going. And, me massively overestimating my skill level, I started hacking away at that Forth interpreter/compiler that I had only a very vague idea of on what it was even supposed to be.
I only had very limited knowledge of compiler building. I had more or less zero knowledge of Forth.
And here is the result. This is the fourth iteration. It works. It's not complete. It's probably messy. It's not very optimized. Documentation might be lacking in places. But it works. It uses only two routines from the WDC monitor (character read and write), so it should be easily adaptable to any 65C02 computer out there. It's not going to work on the classic 6502 since I use some 65C02 exclusive commands (PHY and such).
I'm posting this here to get some reactions from you. Whether it's encouragement, constructive criticism or that you actually installed this thing somewhere and got it to work. Saying hi is also welcome.
I have no fancy Github page, so I will put future versions here in this thread.
I used a Mac mini M2 Pro as a cross development machine. I programmed dawnFORTH using the Vim/MacVim editor. The source was assembled using the vasm cross assembler. I wrote two little scripts to assist me with assembling and uploading the code to the board. The main uploading script was graciously provided to me by David Gray from WDC, he gave me his permission to upload it, so you can find at the bottom of this post.
Please let me know what you think. See you on the forums.
vasm webpage: http://sun.hasenbraten.de/vasm/
To make the correct vasm that works with my code I use:
Code: Select all
make CPU=6502 SYNTAX=std
Code: Select all
vasm6502_std -c02 -Fbin -foenix-pgz -exec=_ENDPROG -o dawn.o dawn.s
Code: Select all
upload.py dawn.o -d /dev/tty.usbserial* -m write -k
vim is part of macOS, but the GUI version MacVim is available here: https://macvim.org
Edit: I forgot to mention one "speciality" of dawnFORTH: It has variable CELL sizes. Default is two bytes, standard 16 bit integer. But you can blow it up to 16(!) bytes if you want to. No re-compile necessary. You can do that by writing the new cell size into CELL. Please let me know what you think of that.
Edit2: Another thing I forgot is that the line editor and EMIT are multibyte character capable. I'm German, so I need my äöüÄÖܧß...
Change History:
20251228-1359 CET+1
- Fixed... annoyance in "ACCEPT", where ACCEPT would use the input buffer pointer instead of a temporary one, leading to the input buffer pointer (thus SOURCE) being overwritten and subsequent input getting store into whatever buffer address you provided to ACCEPT.
- Fixed bug in "int_header" that would produce a random code address when called by ":NONAME".
- Fixed bug in "int_insertXT" that would produce an incorrect XT when paired with ":NONAME".
- Fixed bug in ">" that would produce incorrect flags with certain values.
- Fixed bug in "ALIGNED" that would incorrectly align an already aligned address, producing "a-addr CELL+".
- Changed "SAVE-INPUT" so it will compress multiple characters into one cell (depending on cell size).
- Added "NAME>STRING".
- Added "U/MOD" and "U/".
20251223-1217 CET+1
- SLITERAL now adds a zero-byte to the end of the string, so EVALUATE will work. This is not reflected in the length value and should be transparent to the user.
- EVALUATE now correctly saves the entire input specification and restores it on exit. Correctly passes the EVALUATE test suite on "forth-standard.org".
- Fixed "lean" to only delete comments. Thank you, Sam.
- Expanded and clarified README.txt.
20251221-2137 CET+1
- Bug fix. Fixed a bug where PARSE, PARSE-WORD would continue to read characters past the end of a string that wasn't zero-delimited.
20251221-0944 CET+1
- POINT UPGRADE. We're at version 0.6 now.
- Added the EXCEPTION word set.
- Realized that I was stupid and removed pushing HERE on the data stack from ALLOT and VARIABLE. Which resulted in a lot of hand wringing and rewriting of code all over the place.
- Optimized multiple functions in "stack.s" and "functions.s" and probably elsewhere.
- Removed "AHEAD", "int_resolveForward" and "int_resolveBackward" from the internal word set. They're now in "system.fth".
- Added "DP@", "DP!", "RP@" and "RP!" to the internal word set.
- Fixed several bugs (as usual).
20251206-1232 CET+1
- I added multi-byte capability to HOLD (and fixed a bug that resulted thereof).
- Added saving and restoring the data stack when using the (currently) one-level undo (accessed by pressing cursor-up on your ANSI terminal).
- Numerous small changes to stuff not worth mentioning.
20251126-0940 CET+1
- Uploaded the Python upload script graciously provided by and with permission of David Gray, WDC.
- Expanded README.txt to include the Python upload script.
- Added more CORE words in "system.fth".
20251125-1035 CET+1
- Worked on and expanded README.txt. Not finished, but has much more information now.
- Cleaned up dawnFORTH folder and resulting zip file. It's much smaller now. No changes to source code.
20251124-1802 CET+1
- Fixed problem where range testing the data stack pointer would corrupt processor flags. Division stopped working due to that.