Yesterday, I shared a silly little project I was undertaking where I was going to port a BASIC program to the Arduino, line-by-line. I am glad to say I have successfully done just that, but the practicality of such accomplishment is very questionable.
For programs that were not created to use 21K of RAM for a memory-resident userlog and message base (like my *ALL RAM* BBS program does), it seems fairly easy to port over Microsoft BASIC code and get it running on the Arduino with surprisingly easy changes. I am tempted to find some classic BASIC programs (like ELIZA or Hunt the Wumpus) and try to convert them, as well, just to see if 2K of RAM is enough for hopefully less memory-hungry code.
So let’s talk a bit about memory. The Radio Shack TRS-80 Color Computer came out in 1980 with a 4K model (later generations would support as much as 512K, or megabytes through third party suppliers). In a 4K system, all of the BASIC code took memory, as well as any variables the program used. I expect working in an Arduino is similar to the 1980 experience, except for more program space.
On a 4K computer, if you had a BASIC program that took up 3K, you only had 1K left for variables. On the Arduino UNO, there is 2K of RAM, and 32K of Flash storage to hold the program. So, that same 3K program that only had 1K of RAM for variables on a 4K CoCo would do much better on an Arduino since it could store the 3K program in Flash, then have the full 2K for variables.
Unfortunately, my BBS program was designed to work on a 32K CoCo. These early 8-bit computers, even with 64K upgrades, still had a BASIC that only recognized 32K (without loading some extra patch program). And, on power up, some of that memory was reserved to hold four graphics pages. Thus, a 32K CoCo would show 24874 bytes available in BASIC.
You could adjust the amount of memory reserved for graphics screens higher or lower with the “PCLEAR” command. A “PCLEAR 8” reduced memory down to 18727 bytes. 6K (6144 bytes, or 1.5K per graphics page) was consumed. For programs not making use of these graphics, we wanted to get rid of that reserve and use it ourselves. Unfortunately, the PCLEAR command only allowed going down to “PCLEAR 1”, which gave 29479 bytes free for BASIC. That’s a nice bit of extra, but someone clever figured out how to achieve a PCLEAR 0 and get the most memory we could use without patching BASIC: 31015 bytes free.
Note that, once you plugged in a Radio Shack Disk Controller and added Disk Extended Color BASIC, the memory available went down a bit due to overhead of supporting the disk system. For this article, we are looking strictly at a circa 1980 style CoCo with a cassette recorder only.
And what does this have to do with the Arduino? I wanted to make sure you understood the limits I was facing when trying to port a cassette based BBS program to a machine with only 2K of RAM (and not all of that is usable by the user program).
My end result was a fully functional clone of the *ALL RAM* BBS, but with some rather impractical limits. For my demo system, I only allocated enough space to support about four users. Even I have more friends than that. And for messages, the limit was about four messages, each having just two or three lines. I would make a comment about how useless this would be, but Twitter seems to have proven people will use something that even gives less space than my 2K BBS.
So how did I do it? One word: gotos. Lots and lots of gotos. My translation was literal. Even though there are much better, more efficient ways to write this program (which I plan to undertake), I thought it would be fun to see just how easily BASIC could be coded in C.
I started out by taking an ASCII listing of the BASIC program, and adding “//” comment markers to the start of each line. I pasted that in to a fresh Arduino sketch, so it looked like this:
//0 REM *ALL RAM* BBS System 1.0 //1 REM Shareware / (C) 1983 //2 REM By Allen Huffman //3 REM 110 Champions Dr, #811 //4 REM Lufkin, TX 75901 //5 CLS:FORA=0TO8:READA$:POKE1024+A,VAL("&H"+A$):NEXTA:EXEC1024:DATAC6,1,96,BC,1F,2,7E,96,A3 //10 CLEAR21000:DIMNM$(200),MS$(19,10),A$,F$,S$,T$,BR$,CL$,NM$,PS$,PW$,A,B,C,CL,LN,LV,MS,NM,KY,UC //15 CL$=CHR$(12)+CHR$(14):BR$="*==============*==============*":GOSUB555 //20 CLS:PRINTTAB(6)"*ALL RAM* BBS SYSTEM":PRINT"USERS:"NM,"CALLS:"CL:PRINTTAB(5)"SYSTEM AWAITING //25 A$="Welcome To *ALL RAM* BBS!":GOSUB1055:KY=0:CL=CL+1 //30 PRINT:PRINT"Password or 'NEW' :";:UC=1:GOSUB1005:PS$=A$:IFA$=""ORA$="NEW"THEN55ELSEPRINT"Checking: ";:A=0
And thus it began. I would go line-by-line and try to write C code for each statement. All C variables would be made global, just like they were in BASIC, and blocks of code called by GOSUBs would become standard C functions (since they return just like BASIC). But, for GOTOs, I decided to just use the C goto, and added labels in the format of “line125:” so I could later “goto line125;” in C.
It looked like it just might work… (And, since I started this story in reverse, you already know that it did, but I will share some of the ways I did it in a future posting.)
Until then… Enjoy having more than 2K of RAM!