Today, I'll go through the details of the source code modifications to build a version of MS BASIC for the 6502 RC2014 system. To recap, you probably want to look at this archeological analysis of MS BASIC for the 6502.
If you haven't seen it yet, I had previously also described the port of Lee Davison's Enhanced BASIC in this article.
My fork of the MS BASIC source code is on GitHub here.
I decided to use the Ohio Scientific (OSI) configuration as the starting point for the adaptation.
defines_osi.c
The first level change is in the defines_osi.s file where you can enable or disable features. You will also customize for your hardware and BIOS entry points here.I started off using CONFIG_SMALL := 0 to use 9-digit floating point but found it to be very slow. So back to 6-digit floating point instead.
The original OSI BASIC was based on MS BASIC 1. To get the "latest/greatest", I used CONFIG_2A to build for MS BASIC 2.
RAMSTART2 is set to the beginning of usable RAM at $400. Remember that the $300 page is used by the Monitor/Debugger.
Finally, the serial input/output routines (MONRDKEY and MONCOUT) point to the BIOS entry points.
osi.cfg
The osi.cfg file defines where in memory the BASIC will reside.- BASROM is set to $5000 which is in RAM: I load the binary to RAM for testing. If you are planning to burn the BASIC image into ROM, you will need to set this value to the start address of where the image will be sitting. For example, if you are replacing EhBASIC on a 6502 RC2014 system, you can set the value to $c100 (current EhBASIC start address).
- Unlike EhBASIC, the OSI build of MS BASIC fits under 8KB, so you can change the size from $2400 to $2000
msbasic.s
After setting up osi.cfg and defines_osi.c, I ran an initial build and hit an error. The .feature force_range was undefined in the version of cc65 that I am using.Solution: comment out the line!!
loadsave.s
The next errors I hit were the undefined functions: LOAD and SAVE.In the more customized versions of MS BASIC, a <platform>_loadsave.s file was used to define the LOAD and SAVE routines. This was pulled into the build process in a series of conditional compile statements in the loadsave.s file.
To fix the problem, I added the following:
.ifdef OSI
.include "osi_loadsave.s"
.endif
osi_loadsave.s
And of course I needed to actually write the LOAD/SAVE routines, which were easy to do (!!):SAVE:
rts
LOAD:
rts
While I was doing that, I added a definition for MONISCNTC. This is a routine to check if CTRL-C has been pressed while a BASIC program is running. We call the non-blocking check_input BIOS API at $ff06 and if there is a keypress, check if it is $03.
osi_iscntc.s
Defining MONISCNTC itself did not enable the use of CTRL-C to break a program. I tried porting over Grant Searle's implementation of the ISCNTC routine but that didn't work either.What worked was a change in osi_iscntc.s to call MONISCNTC as a subroutine vs a jmp. Thus:
ISCNTC:
; jmp MONISCNTC
jsr MONISCNTC
nop
nop
nop
nop
lsr a
bcc RET2
jsr GETLN
cmp #$03
When I have time, I'll dig into this a little further...
inline.s
The last functional fix was in inline.s to enable the use of the backspace key for editing. I added an OSI build condition to the INLINAIM routine to check for a backspace character.header.s
Now that I had everything building and actually running, the next step was to make it all easier to use.There is no fixed entry point to MS BASIC. Every time after making a code change, I had to look in the osi.lbl file to find the address of the COLD_START routine.
On the other hand, the RC2014 Z80 MS BASIC puts the cold start entry point at the start of the binary image. I used the same approach with my port of Enhanced BASIC.
To make this change, I added the following to the header.s file:
.ifdef OSI
jmp COLD_START
jmp RESTART
.endif
The BASIC entry point is now at the start of the BASIC binary image. This is a jmp to the actual cold start entry point. The warm start entry point is 3 bytes after the start of the binary image. This is again a jmp to the actual warm start routine.
Let's talk about the build scripts next.
make.sh
I changed the original make.sh build script to enable a detailed assembly listing of each variant of BASIC.By default, the script builds for all the platforms. After each platform is built, the resulting bin and lbl files are copied to the tmp directory. The list (msbasic.lst) file is not copied and is overwritten when the next platform is built. The change to make.sh is to also copy the msbasic.lst file to the tmp directory. This makes debugging conditional builds a lot easier.
buildit.sh
This is my top level build script.Since I am uploading the BASIC binary to RAM for testing, I convert it to Intel Hex format using a bin2hex tool.
The latter is based on a Python library. My fork of that code is here.
Conclusion
The final MS BASIC build file (osi.hex) has been uploaded to GitHub.Use the Monitor/Debugger to upload it to address $5000, then use the 'G' command to launch it:
g 5000
When prompted for "MEMORY SIZE?" type in 8192. This will prevent the BASIC initialization routine from clobbering the BASIC code in RAM. If you are running BASIC in ROM, you can just hit <ENTER> at the prompt.
When prompted for "TERMINAL WIDTH?", just hit <ENTER>.
At that point, you will see the Microsoft copyright message.
This is what I get on my terminal emulator:
The key difference with the RC2014 Z80 MS BASIC is that lowercase is not recognized for program keywords and variable names. You have to use uppercase characters.
Enhanced BASIC has the same limitation.
In terms of performance, MS BASIC for the 6502 is almost 0.3 seconds slower than Enhanced BASIC and 1/2 a second slower than Z80 BASIC running the same prime number benchmark.
NEXT
I will build a ROM image with MS BASIC+Monitor/Debugger for the 6502 RC2014 system.Watch this space!!
I agree with you. That is a very valid point you bring up. Thank you for sharing this very informative and well explained post with us.
ReplyDelete......................
Cloud Security Traning
Try BBC-Basic for the 6502 and you ll never use M$-Stuff again!
ReplyDelete