ASSEBLY LANGUAGE PROGRAMMING PART FIVE - NEW KIND OF INTERFACE As noted last time, I will be presenting a new method of calling subroutines. This method does have a few drawbacks but they are usually outweighed by the advantages. Before I present a discussion of the merits of this system, I will first explain it. The 6809 processor handles events called "interrupts" which happen for various reasons. What happens when an interrupt occurs is the 6809 drops whatever it is doing and proceeds to follow a set of instructions which are called an interrupt handler. Most interrupts can be prevented from interrupting the processor by disabling them. This is not normally done because interrupts can provide useful timing information or handle events that happen at unknown intervals. This removes the need for the programmer to check for all these events. There are two types of interrupt. One is a hardware interrupt which is generated by some device that is physically part of your computer. These interrupts usually have priority. The other is a software interrupt which is generated by an assembly language instruction. The 6809 has three such instructions: SWI, SWI2, and SWI3. The first one has a one byte code while the other two have two-byte codes. From this point forward, this discussion will be limited to software interrupts. When an interrupt occurs, the 6809 looks up the address at which is must start executing the interrupt handler. The 6809 expects this table of addresses to be at $FFF0 in its logical address space. It then proceeds to execute whatever instructions or garbage happens to be at the location specified by the apporpriate entry in that table. It is imperative that the interrupt servicing routine always be present in memory otherwise the interrupt could end up executing garbage. The interrupt routine usually ends with an RTI (return from interrupt) instruction which returns control back to wherever the CPU left off. Since an interrupt can occur at any time, steps must be taken to insure that the interrupt routine does not tamper with the state of the processor. This is, however, not possible so another method is used. When the interrupt occurs, ALL the registers are stored on the stack along with the location of the next instruction to execute. (Actually, one interrupt behaves diffently, but that is beyond the scope of this article). Also, to prevent the routine from interrupting itself, interrupts are disabled when it starts. This is the reason a separate instruction is needed to return from an interrupt. It should be noted that even though an interrupt is not supposed to modify the state of the processor, it is possible to do so. Since the state is stored on the stack, it is possible to change the value of any register by changing the appropriate location on the stack. It is also possible never to return from the service routine, but that is not recommended, either. These rules can be bent with relatively few side effects with software interrupts, however. In fact, this method of calling routines is exactly that. It breaks the rule that an interrupt should not modify the state of the processor. We are going to install a routine that handles the SWI interrupt. It will assume that the byte following the interrupt is a selector which determines what action the service routine takes. Calls to this service routine will re-enable the hardware interrupts just to be polite (except when there is a need to disable them). The routine presented at this time will assume that it can use the area of memory starting at $7800 in the regular BASIC address space. This is just to make the coding much easier. There are several advantages to this method of accessing subroutines. The first and foremost is that no pains need be taken to ensure that the code always occupies the same location. The other big advantage is that the details of the implementation can be completely hidden from the program using the subroutines. Should the interface to the actual code change, the interface to the interrupt handling routine will not. The last advantage is ease of use. Macros can be set to replace the cryptic SWI FCB $00 with something more obvious like CLRMEM which is obviously much more easily understood. An interesting side effect of this method of operating is that one can pass constant parameters in the bytes following the operation specifier. If you have dynamic data, you can use a pointer to it instead of constant data. Note that the routine you are calling must expect this data to be there before it will work, though. Unfortunately, this method has some disadvantages that must be considered as well. If the routine being accessed is very short, the overhead time used calling it in this manner can be hundreds of times longer than the routine itself takes to execute. If the routine is complex of long enough, this is not a consideration, though. The other disadvantage is that the routines are much harder to write. If, after weighing the advantages and disadvantages of these methods you determine that it is the correct method of doing what need doing, then by all means, use it. And now, how do we make this method work? Well, as seems to be the trend, I am going to point you to the code in PART5.ASM as it is well documented. The main flow, however, is as follows: 1. get the operation code 2. determine which routine to execute 3. execute the routine 4. return from the interrupt Until next time, keep programming.