Tandy gram; using vectors to disable the break key. Jake Commander.
I forgot to say it last month, but I'll get it in while it's still early in the year: I hope that 1985 will be a better one for microcomputing. Without a doubt, 1984 hurt many businesses in the industry. The year saw what was called a big shakeout (a self-fulfilling prophesy if ever I saw one).
Thankfully, due to the size of the corporation, (and I'm sure the management would also like to claim some responsibility) Tandy was dented only minimally during a year which saw the demise of many microcomputer-related companies. We lost quite a few magazines, too.
So everybody knock on wood; we've a lot to be thankful for in the TRS-80 world. As an interesting aside to the main direction of the column this month, I've shown some figures for Tandy's growth over the last three years which seem to indicate that the company is weathering the storm respectably. Back to the Break Key
Back to the main thrust as promised last month. After a good break, you should be ready for another--but this time, the Break key. If you read the column last month, you will recall that I'm looking at ways of commandeering the Break key during the execution of a Basic program. The idea is not to lock it out for security reasons but simply to protect the user of a program from landing in the lap of Basic.
This may be no big deal to seasoned programmers, but you don't have to be literate in Basic to run an accounts payable package, and an operator of such a program deserves something better than beign tossed out of a familiar program environment just because he accidentally hit the wrong key. Moreover, creative use of the Break key can deliver all sorts of benefits in a Basic program. That is why many dialects of Basic now feature an ON BREAK GOTO command. By following the logic about to follow, users of the Models I/III/4 and Color Computers will have an equivalent feature.
I freely admit that I didn't anticipate the circuitous route I ended up taking in the solution of this problem. When I wrote about "another method" in last month's column, I knew what I meant, but those comments look like bravado after what I've just been through.
Many surprises were lurking in bits of interpreter machine code. Some of them took me by surprise; so much so that I ended up spending ten times my estimated time on this project. If it hadn't been for my disassemblies of the Basic ROMs, I wouldn't have finished this for about another two months.
Let me explain what the technique we're looking at is all about. If you remember, last month we redirected the RST 40 processing on the Model I/III/4 (from here on, I'll just say Model 4). This RST 40 had relevance only because it is invoked at the machine code level whenever the Break key is hit. There is no magic behind this; it is simply there in ROM on the Model 4. Whoever wrote the code in those ROMs meant for a RST 40 to occur whenever Break was pressed. Even better as far as our designs go, the RST 40 vectors out through RAM. Vectors Explained
Now I've said it: vectors out. That's what this technique relies on: vectors. As I remember from my high school math, vectors are quantities that have both magnitude and direction. In the computer-related use of the word, they have only direction. (Maybe what happens at the other end qualifies as magnitude.)
Vectors are merely jumps to machine code routines. By virtue of the fact that they are there to be changed if desired, they are always in RAM. Vectors are useful because by changing them, the behavior of particular routines can be altered in a predictable fashion.
For instance, many programs have RAM vectors to the input or output routines. By changing the keyboard input vector to point at an RS-232 input routine, a program which normally receives keyboard input can be operated remotely--just by changing the direction of the vector. Remember, a vector is only a jump; hence the idea of direction. In this example the jump would go to a serial input routine rather than a keyboard one.
Their versatility and ease of use is why vectors are considered good programming practice. The point is that the vectors have to be consciously put there to make this versatility available. Without them in a ROM-based system, you are stuck with whatever is burned into the ROM. Fortunately for us, they are present in our ROM Basic interpreters.
The name given to this seemingly nefarious activity has a ring of felony about it: vector stealing. I just love that description. I rub my hands together in glee every time I steal a vector and achieve an increase in the performance of my computer. Vector Theft
So, let's steal some vectors. I should say that sometimes it is not necessary actually to steal. A wiser approach is often to borrow. The following examply will show you what I mean.
Imagine, as I just described, that somewhere a keyboard input vector was "stolen" to facilitate serial input instead. It is the word "instead" that results from vector stealing. By replacing the vector which does a "jump to keyboard scan" with one that does a "jump to serial scan," you lose the ability to communicate via the keyboard.
However, if the "jump to keyboard" is placed at the end of the serial input scan, the keyboard is scanned as before if no serial input is available. Thus, you have both keyboard and serial input available. This is more accurately described as borrowing rather than stealing. When I first got my Color Computer, I used the exact scenario described to enter programs from my Model I into the Color Computer without losing my Color Computer keyboard input.
Within the basic interpreters of both the 6809 and the Z80 machines, Tandy installed quite a few vectors from ROM into RAM. Usually these vectors point straight back into ROM routines until a disk unit is installed. Then they point to upgraded routines in the disk operating system. The problem is that to discover where the vector are placed and what their intended use is, I had to disassemble and document the Model I and Color Computer ROMs. This is guaranteed to fry many brain cells, and the only reason I did it was because I thoroughly disliked not knowing what was going on inside those machines.
Among the vectors I found was one that does exactly what we want here. It allows some kind of processing to be done between each and every Basic statement in a program, including statements between colons. In the Model 4, this vector is at 41C4. In the Color Computer it is at location 019A. This vector points to a routine that does the particular keyboard scan which allows a BREAK, a PAUSE, or an INKEY to occur. Perfect. Redirect this vector, and we can trap the Break key ourselves. Not only that, but we'll be trapping the Break key only during execution of a Basic program. The Snag
Like a good guy, I tried borrowing the vector as I described. Both attempts on the Model 4 and Color Computer ended in abject failure. It took hours of poring over disassemblies to find out why. For the record, here's what I found.
On the Model 4, I run under LDOS. This DOS uses the vector for its own Break trapping and was liable under certain circumstances to seem to fabricate a BReak out of thin air. In reality, it was reacting to the very Break I had just trapped because it scans for that key during interrupts. As it was going behind my back despite the fact that I borrowed and didn't steal, I went ahead and stole.
Using my method here, LDOS (and whatever DOS you use) won't get a chance to do any inter-statement processing of its own. This routine takes total control. Listing 1 shows the machine code which is redirected to by the vector at 41C4.
The first thing it does is to check if two calls back were made from within the interpreter at 1D1E--the inter-statement processor. This little bit of code is necessary because the same vector at 41C4 is used between the lines of a listing to allow PAUSE or BREAK (and also INKEY!) between lines of a listing. If we did come from the right place, we do our own key scan. Now if Break is detected, we load the DE register pair with the desired line number and make a beeline for it. It looks so easy after it has all been researched.
The Basic program to PKE this machine code routine into a string and then execute it is shown in Listing 2. Somewhere after the number 17, you will see the numerals 4 and 1. This is the line number to jump to in Z80 order ("4" + "1" * 256). Change these if you want a different line number. However, remember last month's caveat about bytes 0 and 34. Color Computer Antics
The Color Computer had even worse tricks up its sleeve. I have no respect for routines which commander the routines I have just commandeered. This is precisely what it did. First I borrowed the vector like a good guy, and then i stole it like a bad one. Both times my machine code was totally ignored--well, not totally.
During the debugging, I placed a CLS call before my Break key scan.
Theoretically, the screen should have cleared between Basic statements. It cleared only once.
I hated this one. Why had I successfully stolen a vector only to be treated as if i wanted to use it only once? Eventually, to my great amusement, i found that Color Extended Basic steals its own vector. And no good guy stuff either--it steals it completely.
So what was happening was that I stole the vector from Basic, and Extended Basic stole the vector back from me. When I borrowed the vector, I was handing that very vector back over on a plate.
Not only that, but when I stole it, it stole it right back. It turned out that as soon as i ran a Basic program, the first colon or end of line vectored to this heartless routine which never used the vector again. This routine did its own Break check, and my routine was cheated. The Solution
The solution is in line 10 of Listing 4. By disabling the vector before even a single end of statement, the nasty routine doesn't get a chance to bypass my efforts. So this line must always be the first one in the program.
Listing 3 shows the machine code, which is POKED and executed. To change the line number jumped to on Break, change the 1 and 4 which occur after the 204 in line 100. In standard 6809 format, this is ("1" * 256 + "4") to give 260 in this example.
Incidentally, both Model 4 and Color Computer Basic programs just run a demonstration program which counts from 1 to infinity. As soon as you hit Break, the count is reset to 1 to show that the Break was actually intercepted.
As I have made this so easy, see if you can work out how to Break out of the program. I have left a window through which it is still possible for a normal Break to occur, but an application user is unlikely to find it. The change required in the machine code to seal this route of escape is dead easy, and I'll leave it as a puzzle to see if you can find it.
Finally, those Tandy performance figures, which i read in Computer Retail News, are in Table 1. Draw your own conclusions, but I must say I find them reassuring considering that miserable 1984.