-OR THE JOY OF USING INTERRUPTS ON YOUR COMPUTER
PART TWO
Response to Part One of this series has been quite gratifying so far. However, from what I’ve heard, it seems that a little “fine tuning” of the format is in order. Essentially, we’ll do fewer things in each installment, stretch the series out longer, and give a little more attention to detail. This’ll give those new to the subject a little more help and time to catch up. It also means that we won’t cover as many things this time as promised, but it will all get done, eventually. Those who are particularly anxious to get on with it should feel free to collar me at SINCUS meetings, with their questions.
I hope readers who own or have access to a TS2040 printer have tried out the demonstrator program. If not, it would be worthwhile to do so before reading further. While we’re discussing the last installment, I’d like to call your attention to the second paragraph in the right hand column on page 8. An important sentence has been left out. It should read, “One thing I haven’t mentioned is that the address assembled from the I-register and the data bus is NOT the address of the interrupt handler! It’s the ADDRESS OF THE ADDRESS of the interrupt handler.”
Now back to the questions:
#6 HOW DOES THE DEMONSTRATOR WORK?
Pretty well! Seriously, let’s first look at what the demonstrator sets up in memory, and then we’ll see how it all works together. Understanding this description will require a bit of knowledge of machine code, but only a bit. The demonstrator has been written to be understood by as wide an audience as possible. (That audience will also need a little persistence, though)
Line 30 CLEARs the necessary space for the interrupt software. Line 40 fills memory locations FE00 to FF00 with FD. Line 50 places a JP FF08 instruction at location FDFD. Lines 60 and 70 load the following machine code, starting at location FF01:
ADDR HEXCODE LABEL MNEMONIC [illegible] 3EFE LD A,FE (1) [illegible] ED47 LD I,A [illegible] ED5E IM 2 [illegible] C9 RET [illegible] F5 PUSH AF (2) [illegible] C5 PUSH BC [illegible] D5 PUSH DE [illegible] E5 PUSH HL [illegible] 3E7E LD A,7F (3) [illegible] DBFE IN A,(FE) [illegible] F6E0 OR E0 [illegible] FEFC CP FC [illegible] 2006 JR NZ,FF1C [illegible] F3 DI (4) [illegible] 06C0 LD B,C0 [illegible] CD050A CALL 0A05 [illegible] E1 POP HL (5) [illegible] D1 POP DE [illegible] C1 POP BC [illegible] F1 POP AF [illegible] C33800 JP 0038
I’ve divided the code into five blocks, whose meaning will be explained shortly.
Line 80 executes machine code at location 65281, which, not so coincidentally, is equal to location FF01 in the machine code listing. Only block #1 is executed, since it ends with a RET instruction. Block #1 loads FE into the I-register, and sets the machine into interrupt mode 2, whose operation was explained last time.
From here on, the TS2068 is doing something new that it does not ordinarily do. Every time an interrupt occurs, the machine has to find out where it is to execute the interrupt code. It gets the upper byte of an address from the I-register and the lower byte from the data bus. This combination is the ADDRESS OF THE ADDRESS of the interrupt handler. It will become clearer (hopefully) as we “walk through” what happens.
When the TS2068 gets an interrupt, it looks to the I-register and the data bus to generate the address FExx, where xx is a number that is not known because the TS2068 mysteriously puts different values on the data bus at different times. The TS2068 will then look to memory location FExx for the address of the interrupt handler, and then run the code wherever that happens to be.
However, the BASIC program filled all memory locations from FE00 to FF00 with the number FD,so no matter what value FExx pens to be, the TS2068 will find FDFD when it looks there! [illegible] is where it will start to execute the interrupt handler.
Unfortunately, FDFD is just 3 bytes less than FE00, where the “kluge block” of FD’s is located. There’s not room for much code, but there’s just enough space for the JP FF08 instruction that the BASIC program put there. This means that the interrupt handler will continue at location FF08, or, block #2 in the machine code listing. (It gets a lot simpler from here on, honest)
If the explanation seems murky so far, it’s O.K. to forget it for awhile. Just take my word for it that the aforementioned code makes it appear that an interrupt will cause code to be executed at location FF08. This is where our true interrupt handler is to be found.
The handler begins with block #2, which saves all of the registers. We do this so that we can leave them as we found them when we’re done. This will ensure that we don’t disrupt the program that was running when the interrupt occurred.
Block #3 reads a small portion of the keyboard. We won’t cover keyboard scanning here (see SYNTAX Feb. 1984 for a tutorial on the subject) but block #3 causes block #4 to be skipped if the BREAK and SYMBOL SHIFT keys are not being pressed simultaneously.
Block #4 causes the screen to be copied. Before CALLing the screen copy routine in ROM, we load B with the number of pixel lines to be copied. Changing this would allow us to COPY part of the screen.
Block #5 prepares the computer to leave our interrupt handler. All registers are restored to their original values. Note that the first item that POPs off the stack is the last item that was PUSHed on. This means the registers must be restored in reverse order.
Ordinarily an interrupt handler ends with RETI (similar to RET) instruction. In this case, we’ll end it with a JP 0038, which jumps to the normal interrupt handler. This allows the [illegible]mal interrupt functions of keyboard scanning and updating the system variable FRAMES to be performed.
#7 YOU MENTIONED COPYING ONLY PART OF THE SCREEN. HOW IS THIS DONE?
By loading a different number into the B register before CALLing the COPY routine. You can change the number of lines printed in the following way. Suppose that LINES=the number of lines of characters (from the top of the screen) that you want to COPY. Just POKE 65304,(8*LINES). The handler is now setup to COPY only part of the screen.
#8 WHAT OTHER THINGS CAN AN INTERRUPT HANDLER DO?
By reading the system variable FRAMES, which is incremented every 1/60th of a second a nice real time clock can be made, that flashes the time up on some unused part of the screen, even when you’re running other programs. FRAMES isn’t updated when the interrupts are disabled, so the clock “stops” whenever you use cassette I/O, the TS2040 printer, or the BEEP command, and resumes when you are done. Still, it’s a free, “software only” clock.
If the interrupt handler were linked to a hardware real time clock, like the one demonstrated by Charlie Koeth at the January SINCUS meeting, the clock wouldn’t stop at all.
Among other uses is an item called a print spooler. Printers are very slow compared to the computers running them, and the computers spend most of their time waiting while the [illegible]nter is running. It’s possible to send LPRINT commands to a [illegible]fer area in memory, and have the interrupt handler “pick up” this data and print it one character per interrupt.
This would allow the printer to run at up to 60 characters per second while you’re doing other things with your computer. In other words, you could be running or entering a program at the same time as the computer is printing something else. Those who’ve used such a feature on an IBM PC or other computer will agree that it is a great time saver.
Another use is a program that reads and “stacks up” keyboard entries before the computer requires them. When an INPUT is needed, it gets it from this stacked up data. This is called a keyboard buffer, and it’s also very convenient.
Since the interrupt is synchronized to the video display, it’s possible to change the BORDER color some fixed time after the interrupt, and obtain a “full screen horizon” that extends into the border area. The Spectrum game “Aquaplane” does this, but the required timing may be different to make the effect work on the TS2068’s 60 Hertz interrupt. (The Spectrum uses a 50 Hertz interrupt.) I’ve not seen the game working on a TS2068, but the effect is still available to us.
These are items that come immediately to mind. Other less obvious uses are out there. One that I’m considering involved my software that makes BASIC work in the 64 column mode. Certain keyboard inputs cause the computer to change a system address table in an undesirable manner. I expect to use the interrupt to “change the table back” before any harm is done.
There are many other uses.
A PROLOGUE
Doug Dewey, member extraordinaire, of the Triangle Sinclair User’s Group, tells me that merely adding pullup resistors to a Spectrum emulator, as suggested last time, doesn’t clear up all of the problems related to certain “unrunnable” Spectrum programs. He’s sending me copies of some programs, and I’ll be checking them out especially in understanding the way the Spectrum handles the data bus during interrupts, and whether my “fix” works as expected on all machines.
Next time (or in later installments) we should be looking at the problems of relocating the demonstrator code, of the (solvable) problem of doing something like the demonstrator on a TS1000, and constructing hardware to make use of the TS2068 non-maskable interrupt. Those looking for a challenge should try to relocate the demonstrator to reside in the 16-32K memory region. When a certain part of the interrupt software resides in the same 16K region as the display file, something interesting happens. It still works, but……
Wes Brzozowski
SINCUS
COMPUTUS INTERRUPTUS
10 REM Demonstrator Program
20 REM Causes a COPY-screen
when BREAK & SYMBOL
SHIFT are pressed at
the same time
30 CLEAR 65020
40 FOR j=65024 TO 65280: POKE
j,253: NEXT j
50 POKE 65021,195: POKE 65022,
8: POKE 65023,255
60 FOR j=65281 TO 65314: READ
k: POKE j,k: NEXT j
70 DATA 62,254,237,71,237,94,2
01,245,197,213,229,62,127,219,25
4,246,224,254,252,32,6,243,6,192
,205,5,10,225,209,193,241,195,56
,0
80 RANDOMIZE USR 65281
Type in and RUN – then load you favorite program – when you want a picture of the maze or etc. PRESS [illegible] and [illegible]