• Please review our updated Terms and Rules here

Expanding TRS-80 Level II BASIC

GK2001

Experienced Member
Joined
Jul 17, 2017
Messages
186
When the interrupt line of a TRS-80 is asserted, Level II BASIC jumps to a location in the area of RAM reserved for the operating system. Interrupts are disabled by default and at this location is a jump instruction which is preset to simply send the program counter back to ROM. To utilise interrupts, you can modify the address value here to redirect to your custom interrupt service routine. Your routine just has to terminate with a jump back to the original ROM address.

I am wondering if the BASIC interpreter loop has a similar cycle. This could theoretically permit the BASIC language to be expanded with machine code routines which load into high memory. For example, you could add new BASIC statements to control custom expansion hardware.

Does anyone out there know if such a provision was included in Level II BASIC?
 
Not exactly. The USR statement to call machine code routines loaded into high memory is what I am currently using, but that does not allow one to add new statements/commands to BASIC. For example I would like to add LINE, CIRCLE, FILL, SOUND, etc statements to the language to control external sound and video hardware. This would(might?) be achievable if the authors of the operating system provided a backdoor into the BASIC interpreter loop in a similar way to what they did for the interrupt function.
 
This was a popular book back in the TRS80 days. It might have the info you're looking for.

 
An interrupt permits a piece of machine code to operate in the background whilst a BASIC program can be running.

For example, the BASIC code could initiate something via a USR call (for example, speaking a phrase or generating a note) and the actual code to perform this is actually executed my machine code and an interrupt from the card. The BASIC program could sit and wait for the transfer to complete, or get on and do something else until the transfer is complete.

An interrupt can't (generally) be used to extend the BASIC language itself.

The BASIC interpreter will (generally) provide a facility for enhancing the language statements and functions as part of the technical documentation.

I have not specifically done this for the TRS80 - but for the NASCOM, Commodore PET and AIM-65.

Dave
 
An interrupt can't (generally) be used to extend the BASIC language itself.

I know this and wasn't suggesting otherwise. I am just curious if there is an entry point into the BASIC interpreter via a RAM location loop-back, like there is for system interrupts.
 
I know this and wasn't suggesting otherwise. I am just curious if there is an entry point into the BASIC interpreter via a RAM location loop-back, like there is for system interrupts.
Yes there are. This, for example, is how Level II BASIC was extended when you loaded Disk BASIC (from TRSDOS), or Level III BASIC (which was also available on tape, as I recall). Each of these added new commands, and extended previous commands as well. Various disk operating systems, like Newdos and Newdos/80, each further extended disk BASIC with new commands and features.

As suggested earlier, the "Microsoft BASIC decoded" books were great resources on this.

Back in the day, I added several extensions to both cassette and disk BASIC to add features (field input, hashing algorithms, etc).
 
The Apple II I think has this feature. Its how they were able to add disk commands to the BASIC when DOS was loaded. I don't recall if BASIC Level II was similarly extended when DOS was loaded, or if all of the DISK commands were part of the ROM. The Apple II had some kind of routine that was like an error fault or something that they could tap into.

But I'm not sure of the details.

Edit: As a followup, looking at that Basic Decoded book, this is exactly what happens. Level II has something that they refer to as "DOS Exits", which are callouts within Level II to handle extensibility (notably adding new Disk commands). You can probably find what you want with further study of that, I just glanced at it.
 
Last edited:
Edit: As a followup, looking at that Basic Decoded book, this is exactly what happens. Level II has something that they refer to as "DOS Exits", which are callouts within Level II to handle extensibility (notably adding new Disk commands). You can probably find what you want with further study of that, I just glanced at it.

Level II BASIC has a number of hooks built into it for adding commands. As above, the primary method was the "L3" hook for, intended for disk BASIC but there were other products that used it; for instance, Microsoft sold "Level III BASIC", a cassette-based extension that added a number of enhanced graphics commands, RS-232 support, etc. You even had devices like the Exatron Stringy Floppy that added BASIC extensions that lived in a ROM that nestled in the little less than 2K available in the memory map between the top of BASIC and the start of I/O. (The stringy floppy required the user to type a SYSTEM command at boot to plumb them in, it wasn't automatic.)

I'm 90+% sure there's at least one article in 80 Microcomputing about how to use this mechanism, but it is of course turning out to be a really difficult thing to Google. But you can definitely do it.
 
The BASIC Decoded book includes a section on adding a SORT command to the BASIC. It might provide a good idea of how much work will be needed to implement the specific desired commands.
 
Recommend the BASIC decoded book. You will need it!
Look for an early version of the book. Later ones have information removed because Microsoft had a hissy fit.

On startup basic preloads a jump table in RAM. The table entries are called at major points in basic.
The default table just returns allowing basic to run the routine in ROM
You can change the return to a jump to replace the function. It's how DOS hooks itself into the ROM.

joe
 
Awesome, thanks all.

I found a *.pdf of Microsoft BASIC Decoded here. Unfortunately the link to the second part containing chapters 7 and 8 appears to be dead.
 
The answer is: yes and no.

The disk basic commands were designed in advance, so all the hooks needed to add its commands and functions were there all the time. But there never was some easy way to replace the main interpreter loop or to add arbitrary new commands.

I know because I did that kind of thing back in the day. The silliest was a "FORGET" statement that worked, but it really slowed things down. But I can't find that anywhere in the rips of all my floppy disks that I made with a catweasel back in 2008 or so. And while I was able to get in there, it wasn't very efficient.

in any case, it would be better to start with Disk Basic or LBasic and add/remove stuff from there. Or wire up your own patched EPROM.
 
Just for interest, there was an 'extended' BASIC, (known as XBAS), for the Aculab Floppy Tape available in the UK, in the day. (AFT, similar to Exatron SF in the USA). Details of the all commands are to be found in the Aculab booklets, on the downloads page at www.trs-80.org.uk. I've tried, in vain, to get a copy of it from one of the many wafers I have but without success. Such a shame really, as that piece of software would be well worth saving for future reference!
 
LSI enhanced MS BASIC for LSDOS 6.3 release. Commands were added I suppose as you want to do here.

I have no idea if BASIC for version 6 had great internal documentation like this or not.

But it would seem that LSI & MISOSYS had source to MS BASIC at one time or some mechanism to add commands.
 

(I found it because I already had a full version, so I googled for its file name.)

And I did find that old code of mine, but of course there are not only very few comments, but three different revisions that I have to diff out.

Thanks for the link. I guess that I still have a lot of reading to do, but if adding new arbitrary commands to BASIC is really cumbersome and sucks up a lot of CPU cycles then that is kind of a show stopper. The USR method that I am currently using may be the most efficient method to control my custom hardware.
 
Most software that added custom commands to BASIC would use the Disk Basic commands for repurposing. That's simply because those had addresses that passed through RAM. The others were in ROM and couldn't be diverted. Even the custom "Sort" command in "Basic Decoded" mentioned above does that--it's secretly using MID$, just not openly. At least there were plenty of disk commands available to use, unlike the Apple II which only had one ("&") that users could customize.

But at least one package used another way...

The Lowe Electronics LE18 high-resolution for the Video Genie clone had software that added drawing commands to Basic, but didn't steal any Disk Basic commands to do it. Instead, the driver chained into RST 10h, which "Basic Decoded" calls "Examine Next Symbol" (pg 27), which the interpreter apparently runs before every command. Essentially, the driver jumps ahead of all processing and checks for the hires commands first, before releasing it back to the original interpreter.

(I didn't even know about the LE18 until it was added to the TRS80gp emulator by the Phillips. You can find the software and more info about it on Knut Roll-Lund's site: http://knut.one/VGShires.htm)

There were lots of tricks to sneak features into Microsoft's interpreter. Just this year I read about the "USRful" patch to the USR command so it could jump directly to an address next to it: like "USR73(A)" to ROM address 73. (In the Dec 1982 issue of 80-US magazine, as well as trs8bit1601.) Again, it hooks the Disk Basic link to the USR command, but with a subtle extension instead of complete replacement.
 
Last edited:
That USR patch looks interesting (starts on page 48 here), but the article doesn't say what range of address values it can handle. I'll have to study the code and try it out.

I really wish POKE could handle two-byte transfers like the Z80's 16-bit load instructions do; like if POKE accepted a data value range of -32767 to 32769 and stuck the low byte into the specified address and the high byte, if the value is outside of the range 0-255, into the next address location up.
 
That USR patch looks interesting (starts on page 48 here), but the article doesn't say what range of address values it can handle. I'll have to study the code and try it out.

I really wish POKE could handle two-byte transfers like the Z80's 16-bit load instructions do; like if POKE accepted a data value range of -32767 to 32769 and stuck the low byte into the specified address and the high byte, if the value is outside of the range 0-255, into the next address location up.
You can, just poke twice.

You can poke 8, 16, 32 or any length of bits you want. As programmer its your responsibilty to convert number to binary then poke in memory (in order).

Most BASIC programming examples include 16 bit conversion routine, if you cannot find one lmk and I will dig out an example.
 
Back
Top