Well. Here it is, the final entry for my Summer Retrochallenge project. I wanted to do more, but as so often happens, real life intervened and I didn’t have nearly as much time to work on it as I’d wanted. C’est la vie!
But I’m still proud of what I accomplished. I have a working ROM monitor, and I’m happy to report that as a final hurrah, I got it fully integrated with Lee Davison’s Enhanced 6502 BASIC.
Integrating with BASIC
I didn’t start this project thinking I’d tackle BASIC integration, but as Retrochallenge drew to a close, it seemed like it might be the best use of my precious time. What I mean by “Integration” here is simply having my ROM monitor code live side by side with BASIC and provide the underlying I/O functionality needed for BASIC to talk to the terminal and get input, plus the ability to take over and run in the foreground when the user wants it.
If you’ve ever used an Apple II, you may recall that it, too, has a built in ROM monitor, and it can be reached by typing CALL -151 into Apple BASIC. Well, when running Enhanced 6502 BASIC with my monitor, you can get the same thing by typing CALL -1239. Once you’re in the ROM monitor, you can quit back to BASIC just by typing Q. Like so:
It actually turned out to be fairly simple to get the integration working.
The first thing I had to do was re-organize my memory usage so as not to conflict with EhBASIC’s memory map:
;;; ----------------------------------------------------------------------
;;; Memory Definitions
;;; ----------------------------------------------------------------------
STRLO = $de ; Low byte of STRING (used by STR macro)
STRHI = $df ; Hi byte of STRING (used by STR macro)
HTMP = $e0 ; Hex parsing temp
OPADDRL = $e1 ; Addr of current operand (low)
OPADDRH = $e2 ; Addr of current operand (high)
OPBYT = $02a0 ; # of bytes parsed in 16-bit operands
TKCNT = $02a1 ; Count of parsed tokens
IBLEN = $02a2 ; Input buffer length
CMD = $02a3 ; Last parsed command
TKST = $02a4 ; Token start pointer
TKND = $02a5 ; Token end pointer
OPBASE = $02a6 ; Operand base
IBUF = $02c0 ; Input buffer base
There’s not much room left in Page Zero after EhBASIC gets done with it, but the locations $DE thorugh $E2 are free, so I made use of them. Page Two is similar, so I stuck my variables all the way up at $02A0 and on.
After that, I had to change the implementation of CIN a little bit, because EhBASIC requires that it not block. Instead, it expects this routine to return immediately and set the Carry flag if a character was read, and clear the Carry flag if no character was read. The new routine looks like this:
CIN: LDA IOST
AND #$08 ; Is RX register full?
BEQ @nochr ; No, wait for it to fill up.
LDA IORW ; Yes, load character.
;;
;; If the char is 'a' to 'z', inclusive, mask to upper case.
;;
CMP #'a' ; < 'a'?
BCC @done ; Yes, done.
CMP #'{' ; >= '{'?
BCS @done ; Yes, done.
AND #$5f ; No, convert lower case -> upper case,
@done: SEC ; Flag byte received, for BASIC
RTS ; and return.
@nochr: CLC
RTS
It’s a little ugly and could easily be optimized at the expense of readability, but hey, it works!
So that’s it. With just those changes, I was pretty much able to integrate the monitor into EhBASIC in just a few hours. As always, all of my code is available on my Git repository for your viewing pleasure.
I’d also like to add that this has been a fantastic Summer Retrochallenge. There were so many amazing projects, I can’t even pick a favorite. I’ve really enjoyed reading what everyone else has been up to, and I’m already looking forward to January. Onward and upward, everyone!
Comments