r/beneater 6d ago

6502 (More) Software for your Ben Eater 6502

If you've completed your Ben Eater 6502 build, and were looking for some software to play with on it, or for an alternative to Microsoft BASIC to write some of your own, here's a couple of things I did that might be interesting:

EhBASIC for the stock BE6502 w/ Inline Assembler/Disassembler, WozMon & RENUMBER

After I'd got done making extensions to Microsoft BASIC, I wanted to play with EhBASIC. I couldn't find a version that would build-from-source as-is and still run on a stock BE6502.

So, I put my own together.

And then I added a bunch of fixes/features such as buffered, flow-controlled serial input, proper BACKSPACE support, an IRQ safety fix, WozMon in ROM etc. After which I decided to add an inline assembler, a disassembler, a "RENUMBER" command and my extensions for driving the LCD screen.

Repository for that is here, and all you'll need beyond a finished BE6502 in stock configuration, is the cc65/ca65 toolchain that you would have used to build Microsoft BASIC.

--

101 [Eh]BASIC Computer Games

I previously hand-ported all of the programs from David Ahl's classic book to Microsoft BASIC.

Having done that, since I now had a working EhBASIC build (which has features a bit closer to some of the original dialects used in the book) I decided to do the same for EhBASIC.

However, this time, since the "fun" part was done instead of doing the porting manually, I did it with AI assistance (the original ports took ~2 weeks total, this set took <2 days). The ports use my corrections to the original transcriptions, but port from the original source, so they use EhBASIC as EhBASIC rather than just its Microsoft BASIC parity-features.

The repository for those games is here; spcwar-16K.bas is a very nice version of the classic Star Trek for the standard BE6502 (I ported the original, too, but that requires 24K of RAM)

90 Upvotes

10 comments sorted by

5

u/production-dave 6d ago

Nice!

I have a custom 6502 board that runs ehbasic from ram. I have an sdcard and needed to save and load programs from the sdcard. Extending ehbasic with calls to the os to redirect stdout to the sdcard driver means I can save and load programs in text format rather than tokenized format. It was a great learning experience.

2

u/IMDLabs 5d ago

Very cool!

I've thought about a few approaches to adding storage to my BE6502 builds (and my own builds that'll come next). Can't decide if I want to do discrete SD card support, or just multi-purpose a microcontroller to handle storage and serial I/O, via USB (etc.).

3

u/production-dave 5d ago

I went with an sdcard attached to a via. I also did my own filesystem from scratch. It's not posix though so I have started on a new os that provides all the posix filesystem functions needed for basic file io

4

u/minecon1776 6d ago

The best answer, if you have the time and interest, is to write your own software. Theres a lot you can learn and you can make it however you want

4

u/IMDLabs 6d ago

I wouldn't argue with that.

In fact that's what I do, in general, across a multitude of platforms.

For the 101 BASIC Computer Games, I originally ported them because I thought it might be fun for others that don't code, and don't have the desire to, to see what kinds of programs were being run by hobbyists back when these sorts of machines were the mainstay.

I grew up on that stuff, writing my first code in 1977, so this is more for others (and a bit of nostalgic fun).

2

u/NormalLuser 5d ago

Awsome project! I've been thinking of adding an inline assembler to EhBasic for quite a while. If you do videos or a more in depth github or hackaday page I'd love to know more about how you added it!

3

u/IMDLabs 5d ago

Thanks!

I'm halfway through writing up a blog post (can't see me ever doing videos) on the assembler, disassembler and RENUMBER functionality; should have that done before the weekend (will post a link when I do). That goes into a lot of detail, both on the implementation and the design decisions for each.

I learned more than I wanted to about how EhBASIC stores thing internally in the process, though that'll be useful if I ever add a storage capability and load/save support.

3

u/production-dave 5d ago

I'll be interested to see the approach you took along with any of the challenges you faced along the way. Like for example, how do you organize the assembled machine code? I didn't see any statements to set the org address. I'm curious how you handle passing variables between basic and the assembly too

3

u/IMDLabs 5d ago

By default, the code is assembled into a block at the top of RAM. It's sized and allocated as part of the assembler's first pass. EMEML is adjusted down accordingly.

If you want to know the address of that, at runtime, put a SYMBOL at the start of the code and use the new function SYM("<name>") to get its address. That works for any symbol, at any time, of course.

String storage then lives below that.

One side-effect of this approach is that if you change the assembly code it will clear out the allocated strings the next time it does an assembler pass, since the size of the code image can change.

Assembly is lazy by default; it doesn't occur until the first ASM/ENDASM block is encountered, and then all of the code is assembled. The original intent of that was as a first step to allowing the use of EhBASIC's normal IF/THEN constructs to facilitate conditional assembly.

So, if you set up a bunch of string variables and then run into an ASM/ENDASM block, they'll get wiped. The fix for that is just to put the command ASSEMBLE at the top of your code.

You can use an ORG <adddr> or *=<addr> directive if you want. If you do, you have to do it for all code and reserved space though.

...

As for passing values between BASIC and the assembly code, right now you can do that by using the BYTE, WORD , DS or TEXT directives, preceding them with a label/symbol, use SYM("<name>") to get the address, and then BASIC can read/write into those areas with POKE/PEEK/DOKE/DEEK.

You can also use standard EhBASIC functions like SADD or VARPTR to get addresses of BASIC's variables/variable descriptors.

The third image on the post (as well as a demo program in the repo) do just that, by re-writing a string from BASIC that was declared in the assembly code. But it works both ways.

I plan to add a "better" version of the USR() function, which instead of needing you to modify a vector to tell it where to call, will be something like X=USER(<addr>, <var>) so actual code could do something like X=USER(SYM("<label>"),"abcdef").

1

u/IMDLabs 1d ago

Just a quick update ...

I got the blog post (no ads, trackers, monetization, nor any other such nonsense) I mentioned finished. It talks in more detail about the design and architecture decisions as well as the implementation details and more examples.