MCS6500

Microcomputer Family

Programming Manual


CHAPTER 9 RESET AND INTERRUPT CONSIDERATIONS 9.0 VECTORS Before developing the concepts of how the MCS650X Microprocessors handle interrupts and start-up, a brief definition of the concept of vector pointers needs to be developed. In the sections on Jumps and Branches, it was always assumed that the program counter is changed by the microprocessor under control of the programmer while accessing addresses which were in program sequence. In order to get the microprocessor started and in order to properly handle external control or interrupt, there has been developed a different way of setting the program counter to point at a specific location. This concept is called vectored pointers. A vector pointer consists of a program counter high and program counter low value which, under control of the microprocessor, is loaded in the program counter when certain external events occur. The word vector is developed from the fact that the microprocessor directly controls the memory location from which a particular operation will fetch the program counter value and hence the concept of vector. By allowing the programmer to specify the vector address and then by allowing the programmer to write coding that the address points to, the microprocessor makes available to the programmer all of the control necessary to develop a general purpose control program. The microprocessor has fixed address in memory from which it picks up the vectors. By this implementation, minimum hardware in the microprocessor is obtained. Locations FFFA through FFFF are reserved for vector pointers for the microprocessor. Into these locations are stored respectively the interrupt vectors or pointers for: non-maskable interrupt, reset and interrupt request. 9.1 RESET OR RESTART In the microprocessor, there is a state counter which controls when the microprocessor is going to use the program counter to access memory to pick up an instruction, then after the instruction is loaded, the microprocessor goes through a fixed sequence of interpreting instructions and then develops a series of operations which are based on the OP CODE decoding. Up to this point, it has been assumed that the program counter was set at some location and that all program counter changes are then directed by the program once the program counter had been initialized. Instructions exist for the initialization and loading of all other registers in the microprocessor except for the initial setting of the program counter. It is for this initial setting of the program counter to a fixed location in the restart vector location specified by the microprocessor programmer that the reset line in the microprocessor is primarily used. The reset line is controlled during power on initialization and is a common line which is connected to all devices in the microcomputer system which have to be initialized to a known state. The initialization of most I/O devices is such that they are brought up in a benign state such that with minimum coding in the microcomputer, the programmer can configure and control the I/O in an orderly fashion. The concept has important systems implications in systems where damage can be done if peripheral devices came up in unknown states. Therefore, in the MCS650X, power on or reset control operates at two levels. First, by holding of an external line to ground, and having this external line connected to all the devices during power up transient conditions, the entire microcomputer system is initialized to a known disabled state. Second, the releases of the reset line from the ground or TTL zero condition to a TTL one condition causes the microprocessor to be automatically initialized, first by the internal hardware vector which causes it to be pointed to a known program location, ana secondly through a software program which is written by the user to control the orderly start-up of the microcomputer system. All of the MCS650X family parts also obey a discipline that while the reset line is low, the system is in a stop or reset state. The microprocessor is guaranteed to be in a Read state and upon release of the reset line from ground to positive, the microprocessor will continue to hold the line in a Read state until it has addressed the specified vectored count location, at which time control of the microprocessor is available to the programmer. NOTE: The MC6800 family also follows this convention. 9.2 START FUNCTION While the reset line is in the low state, it can be assumed that internal registers may be initialized to any random condition; therefore, no conditions about the internal state of the microprocessor are assumed other than that the microprocessor will, one cycle after the reset line goes high, implement the following sequence: Example 9.1: Illustration of Start Cycle Cycles Address Bus Data Bus External Operation Internal Operation 1 ? ? Don't Care Hold During Reset 2 ? + 1 ? Don't Care First Start State 3 0100 + SP ? Don't Care Second Start State 4 0100 + SP-1 ? Don't Care Third Start State 5 0100 + SP-2 ? Don't Care Fourth Start State 6 FFFC Start PCL Fetch First Vector 7 FFFD Start PCH Fetch Second Vector Hold PCL 8 PCH PCL First Load First OP CODE OP CODE The start cycle actually takes seven cycles from the time the reset line is let go to TTL plus. On the eighth cycle, the vector fetched from the memory location FFFC and FFFD is used to access the next instruction. The microprocessor is now in a normal program load sequence, the location where the vector points should be the first OP CODE which the programmer desires to perform. The second point that should be noted is that the microprocessor actually accesses the stack three times during the start sequence in cycles 3, 4 and 5. This is because the start sequence is in effect a specialized form of interrupt with the exception that the read/write line is disabled so that no writes to stack are accomplished during any of the cycles. 9.3 PROGRAMMER CONSIDERATIONS FOR INITIALIZATION SEQUENCES There are two major facts to remember about initialization. One, the only automatic operations of the microprocessor during reset are to turn on the interrupt disable bit and to force the program counter to the vector location specified in locations FFFC and FFFD and to load the first instruction from that location. Therefore, the first operation in any normal program will be to initialize the stack. This should be done by having previously decided what the stack value should be for initial operations and then doing a LDX immediate of this value followed by a TXS. By this simple operation, the microprocessor is ready for any interrupt or non-maskable interrupt operation which might occur during the rest of the start-up sequence. Once this is accomplished, the two non variable operations of the programmer control and the stack is initialized and under program control. The next operations during the initialization sequences will consist of configuring and setting up the various control functions necessary to perform the I/O desired for the microprocessor. Specific discussion for considerations regarding the start-up are covered in Section 11. The major things which have to be considered include the current state of the I/O device and the non destructive operations that will allow the state to be changed to the active state. The initialization programs mostly consist of loading accumulator A immediately with a bit pattern and storing it in the data control register of an I/O device. Note: The interrupt disable is automatically set by the microprocessor during the start sequence. This is to minimize the possibility of a series of interrupts occurring during the start-up sequence because of uncontrolled external values although it is usually possible to control interrupts as part of the configuration. The programmer should consider two effects. First, that the non maskable interrupt is not blockable by this technique since it would be possible to configure a device that was connected to a non maskable interrupt and have to service the interrupt immediately. Secondly, the mask must be cleared at the end of the start sequence unless the user has specific reason to inhibit interrupts after he has done the start-up sequence. Therefore, the next to last instruction of the start-up sequence should be CLI. It should be noted that the start-up routine is a series of sequential operations which should occur only during power on initialization and is the first step in the programmed logic machine. Because the execution of the routine during power on occurs very seldom in the normal operation of the machine, the coding for power on sequence should tend to minimize the use of memory space rather than speed. The last instruction in the start-up sequence should initialize the decimal mode flag to the normal setting for the program. The next instruction should be the beginning of the user's normal programming for his device, everything preceding that being known as "housekeeping." 9.4 RESTART It should be noted that the basic microprocessor control philosophy allows for a single common reset line which initializes all devices. This line can be used to clear the microprocessor to a known state and to reset all peripherals to a known state; therefore, it can be used as a result of power interruption, during the power on sequence, or as an external clear by the user to re-initialize the system. As discussed in the hardware manual, restart is often used as an aid to making sure the microprocessor has been properly interconnected and that programs have been loaded in the correct locations. 9.5 INTERRUPT CONSIDERATIONS Up until this point, the microprocessor has to proceed under programmer control through a variety of sequences. The only way for the programmer to change the sequence of operations of the microprocessor was to change the program counter location to point at new operations. The microprocessor is in control of fetching the next instruction at the conclusion of the current instruction. The only way that external events could control the microprocessor, if it were not for interrupts, would be for the programmer to periodically interrupt or stop processing data and check to see whether or not an extemal event which might cause him to change his direction has occurred. The problem with this technique is that I/O events are usually asynchronous, i.e., not timed with the microprocessor internal instructions, thererore, it would be possible for the event to occur shortly after the programmer has stopped to look at I/O events which would mean that the event would not be sampled until the programmer took the time to stop his coding and sample again. Because the sampling of I/O devices normally takes several byte counts or cycles to accomplish, the frequent insertion of checking routines into straight line code results in significant delays to the entire program. In trying to use this technique, there has to be a trade-off between the fact that the program wastes a significant amount of time checking events which have not yet occurred versus delaying checking of an event which has occurred and if not timely serviced the data may be lost. In order to solve this dichotomy, the concept of interrupt is used to signal the microprocessor that an external event has occurred and the microprocessor should devote attention to it immediately. This technique accomplishes processing in which the microprocessor's program is interrupted and the event that caused the interrupt is serviced. Transferring most of data and control to I/O devices in an interrupt driven environment will usually result in maximum program and/or programmer efficiency. Each event is serviced when it occurs which means there is a minimum amount of delaying in servicing events, also a minimum amount of coding because of elimination of the need to determine occurrence of several events simultaneously; each interrupting event is handled as a unique combination. It is possible to interrupt an interrupt processing routine and, therefore, all the interrupt logic uses the stack which allows processing of successive interrupts without any penalty other than increasing the stack length. A real world example of an event which should interrupt is when the user is given a panic button indicating to the microcomputer some event has occurred which requires total immediate attention of the microprocessor to solving that problem. The action and events are as follows : The microprocessor user pushes the panic button; the panic switch sensor causes an external device to indicate to the microprocessor an interrupt is desired; the microprocessor checks the status of the internal interrupt inhibit signal; if the internal inhibit is set, then the interrupt is ignored. However, if it is reset or when it becomes reset through some program reaction, the following set of operations occur: Example 9.2: Interrupt Sequence Cycles Address Bus Data Bus External Operation Internal Operation 1 PC OP CODE Fetch OP CODE Hold Program Counter, Finish Previous Operation 2 PC OP CODE Fetch OP CODE Force a BRK, Instruction, Hold P-Counter 3 01FF PCH Store PCH on Stack Decrement Stack Pointer to 01FE 4 01FE PCL Store PCL on Stack Decrement Stack Pointer to 01FD 5 01FD P Store P on Stack Decrement Stack Pointer to 01FC 6 FFFE New PCL Fetch Vector Low Put Away Stack 7 FFFF New PCL Fetch Vector High Vector Low → PCL and Set I 8 Vector OP CODE Fetch Interrupt Increment PC to PCH PCL Program PC + 1 As can be seen in Example 9.2, the microprocessor uses the stack to save the reentrant or recovery code and then uses the interrupt vectors FFFE and FFFF, (or FFFA and FFFB) , depending on whether or not an interrupt request or a non maskable interrupt request had occurred. It should be noted that the interrupt disable is turned on at this point by the microprocessor automatically. Because the interrupt disable had to be off for an interrupt request to have been honored, the return from interrupt which loads the processor status from before the interrupt occured has the effect of clearing the interrupt disable bit. After the interrupt has been acknowledged by the microprocessor by transferring to the proper vector location, there are a variety of operations which the user can perform to service the interrupt; however, all operations should end with a single instruction which reinitializes the microprocessor back to the point at which the interrupt occurred. This instruction is called the RTI instruction. 9.6 RTI - RETURN FROM INTERRUPT This instruction transfers from the stack into the microprocessor the processor status and the program counter location for the instruction which was interrupted. By virtue of the interrupt having stored this data before executing the instruction and the fact that the RTI reinitializes the microprocessor to the same state as when it was interrupted, the combination of interrupt plus RTI allows truly reentrant coding. The symbolic notation for RTI is ↑P ↑PC. The RTI instruction reinitializes all flags to the position to the point they were at the time the interrupt was taken and sets the program counter back to its pre- interrupt state. It affects no other registers in the microprocessor. RTI is a single byte instruction and its addressing mode is Implied. In the following example, we can see the internal operation of the RTI which restores the microprocessor: Example 9.3: Return from Interrupt Cycles Address Bus Data Bus External Operation Internal Operation 1 0300 RTI Fetch OP CODE Finish Previous Operation, Increment PC to 0301 2 0301 ? Fetch Next OP CODE Decode RTI 3 01FC ? Discarded Stack Increment Stack Fetch Pointer to 01FD 4 01FD P Fetch P Register Increment Stack Pointer to 01FE 5 01FE PCL Fetch PCL Increment Stack Pointer to 01FF, Hold PCL 6 01FF PCH Fetch PCH M→PCL, Store Stack Pointer 7 PCH PCL OP CODE Fetch OP CODE Increment New PC Note the effects of the extra cycle (3) necessary to read data from stack which causes the RTI to take six cycles. The RTI has restored the stack, program counter and status register to the point they were at before the interrupt was acknowledged. There is no automatic save of any of the other registers in the microprocessor. Because the interrupt occurred to allow data to be transferred using the microprocessor, the programmer must save the various internal registers at the time the interrupt is taken and restore them prior to returning from the interrupt. Saving of the registers is best done on the stack as this allows as many consecutive interrupts as the programming will allow for. Therefore, the routines which save all registers and restore them are as follows: Example 9.4: Illustration of Save and Restore for Interrupts Cycle Bytes 3 1 SAVE PHA Save A 2 1 TXA Save X 3 1 PHA 2 1 TYA Save Y 3 1 PHA 13 5 4 1 RESTORE PLA Restore Y 2 1 TAY 4 1 PLA Restore X 2 1 TAX 4 1 PLA Restore A 16 5 The SAVE coding assumes that the programmer wants to save and to restore registers A, X and Y. It should be noted that for many interrupts, the amount of coding that has to be performed in the interrupt is fairly small. In this type of operation, it is usually more desirable to shorten the interrupt processing' time and not use all of the registers in the machine. Therefore, a more normal interrupt processing routine would consist of just saving registers A and X which means that the restore routine would be just restore registers X and A. This has the effect of shortening the interrupt routine by two bytes, and also shortens the restore routine by two bytes and will cut 5 cycles out of the interrupt routine and 6 cycles out of the restore routine. This technique combined with automatic features of the interrupt and the RTI allows multiple interrupts to occur with successive interrupts interrupting the current interrupt. This is one of the advantages of the use of the stack so that as many interrupts can interrupt other interrupts as can be held in the stack. The stack contains six bytes for every interrupt if all registers are saved, so 42 sequences of interrupts can be stored in one page. However, in more practical situations, consecutive interrupts hardly ever get more than about three deep. The advantage of allowing an interrupt to interrupt an interrupt is that the whole concept behind the interrupt is that asynchronous events can be responded to as rapidly as possible; therefore, it is desirable to allow the processing to service one interrupt to be interrupted to service the second, as long as the first interrupt has been properly serviced. To review how this is accomplished using the normal interrupt capability of the MCS650X, it is important that we review the bus concept which is inherent in the MCS6500 family and which is compatible with the M6800. As has already been discussed, all I/O operations on this type of microprocessor are accomplished by reading and writing registers which actually represent connections to physical devices or to physical pins which connect to physical devices. Up until this point, this discussion has addressed itself to transferring of data into and out of the microprocessor. However, there is a concept that is inherent in the bus discipline that says that whenever an interrupt device capable of generating an interrupt desires to accomplish an interrupt, it performs two acts; first, it sets a bit, usually bit 7, in a register whose primary purpose is to communicate to the microprocessor the status of the device. The interrupting device causes one of perhaps many output lines to be brought low. These collector-or'd outputs are connected together to the IRQ pin on the MCS650X microprocessor. The interrupt request to the MCS650X is the IRQ pin being at a TTL zero. In order to minimize the handshaking necessary to accomplish an interrupt, all interrupting devices obey a rule that says that once an interrupt has been requested by setting the bit and pulling interrupt low, the interrupt will be held by the device until the condition that caused the interrupt has been satisfied. This allows several devices to interrupt simultaneously and also allows the microprocessor to ignore an interrupt until it is ready to service it. This ignoring is done by the interrupt disable bit which can be set on by the programmer and is initialized on by the interrupt sequence or by the start sequence. Once the interrupt line is low and interrupt disable is off, the microprocessor takes an interrupt which sets on the interrupt disable. The interrupt disable then keeps the input low line from causing more than one interrupt until an interrupt has been serviced. There is no other handshaking between the microprocessor and the interrupting device other than the collector-or'd line. This means that the microprocessor must use the normal addressing registers to determine which of several collector-or'd devices caused the line to go low and to process the interrupt which has been requested. Once the processor has found the interrupting device by means of analyzing status bits which indicates an interrupt has been requested, the microprocessor then clears the status by reading or writing data as indicated by the status register. It should be noted that a significant difference between status registers and data registers in I/O devices is that status registers are never cleared by being read, only by being written into or by the microprocessor transferring data from a data register which corresponds to some status in the status register. Detailed examples of this interaction are discussed in Chapter 11. The clearing of the status register also releases the collector-or'd output thereby releasing the interrupt pin request. The basic interaction between the microprocessor and interrupting device is when interrupting device sets the status bit and brings its output IRQ line low. If its output IRQ line is connected to the microprocessor interrupt request line, the microprocessor waits until the interrupt disable is cleared, takes the interrupt vector, and sets the interrupt disable which inhibits further interrupts in the IRQ line. The microprocessor determines which interrupting device is causing an interrupt and transfers data from that device. Transferring of data clears the interrupt status and the IRQ pin. At this point, the programmer could decide that he was ready to accept another interrupt even though the data may have been read but not yet operated on. Allowing interrupts at this point, gives the most efficient operation of the microprocessor in most applications. There are also times when a programmer may be working on some coding the timing of which is so important that he cannot afford to allow an interrupt to occur. During these times, he needs to be able to turn on the interrupt disable. To accomplish this, the microprocessor has a set and clear interrupt disable capability. 9.7 SOFTWARE POLLING FOR INTERRUPT CAUSES As was indicated above, any one of several devices are collector-or'd to cause an IRQ. The effect of any one of the devices or combination of them having polled the IRQ line low is always the same. The interrupt stores the current status of the program counter and processor on the stack and transfers to a fixed vector address. In servicing the interrupt, it is important to save those registers which will be used in the analysis of the interrupt and during the interrupt processing, so the normal first steps of the interrupt routine are to do the SAVE procedures. The next operation is to determine which of the various potential interrupting devices caused the interrupt. To accomplish this, the programmer should make use of the fact that all interrupting devices signal the interrupt by a bit in the status register. All currently implemented 6800 and 6500 peripherals always have interrupt indicators; either bit 7 or bit 6 in their status register. Therefore, the basic loop that a user will use to verify the existence of an interrupt on one of five devices is as follows: Example 9.5: Interrupt Polling No. of Bytes Cycles 3 4 LDA Status 1 2 2 BMI FIRST 3 4 LDA Status 2 2 2 BMI SECOND 3 4 LDA Status 3 2 2 BMI THIRD 3 4 LDA Status 4 2 2 BMI FOURTH 3 4 LDA Status 5 2 2 BMI FIFTH RES1 JMP to RESTORE FIRST LDA DATA 1 CLI Process 1 etc. In this example, the simplest case where the potential interrupts are indicated by bit 7 being on, has been assumed. This allows advantage to be taken of the free N-bit test by following the load of the first status register with a branch on result minus. If the first device has an active interrupt request, the BMI will be taken to FIRST where the data is transferred. This automatically clears the interrupt for the first device. To allow multiple interrupts, the load A is followed by the CLI instruction which allows the program to accept another interrupt. As a result of the CLI, one of two things can occur; there is not another interrupt currently active, in which case, the microprocessor will continue to process the first interrupt down to the point where the interrupt is complete and the first subroutine does a jump to RESTORE, which is the routine that unsaves the registers that were used in the process of servicing the interrupt. If another device has an active interrupt which occurred either prior to the first interrupt or subsequent to it but before the microprocessor has reached the point where the CLI occurs , then the microprocessor will immediately interrupt again following the CLI, go back and save registers as defined before and come back into the polling loop. Therefore, multiple interrupts are serviced in the order in which they are looked at in polling sequence. Polling means that the program is asking each device individually whether or not it is the one that requested an interrupt. It should be noted that polling has the effect of giving perfect priority in the sense that no matter which two interrupts occur before the microprocessor gets to service one, the polling sequence always gives priority to the highest priority device first, then the second, then the third, etc. In light of the fact that this polling sequence requires no additional hardware to implement other than is available in the interrupting devices themselves, this is the least expensive form of interrupt and the one that should be used whenever possible because of its independence from external hardware. Although it would appear that the last interrupting device in a sequence pays a significant time penalty based on the amount of instructions to be executed before the last device is serviced, the amount of time to perform polls is only six cycles per device and, therefore, the extra penalty that the last device has to pay over the first device is 24 cycles. This is in comparison to a minimum time to cause an interrupt (eight cycles) , plus store time for registers (in the range of another 8 to 13 cycles) which means that the delay to the last devices is roughly twice what it would be for the first device. This timing just described represents a most interesting part of the analysis of interrupts for a microprocessor. There is a significant amount of fixed overhead which must be paid for the interrupt. This overhead includes the fact that the interrupts can only occur at the end of an instruction so, therefore, if an interrupt occurs prior to the end of an instruction, the microprocessor delays until the end of the instruction to service it. Therefore, in doing the worst case analysis, one has to consider the fact that the interrupt might be occurring in the middle of a seven cycle, read/modify/write instruction which means that the worst case time to process the first instruction in an interrupt sequence is 14 cycles (7 cycles plus the 7 cycles for the interrupt). In light of the fact that saving of additional registers is often required (at least the accumulator A must be saved), at least twice the number of cycles will be required. Consequently the absolute minimum worse case time for an interrupt is 17 cycles plus the time to transfer data which is another 4 cycles. Therefore interrupt driven systems must be capable of handling a delay of at least 20 cycles and more realistically, 20 to 50 cycles before the first interrupt is serviced. This means that devices which are running totally interrupt driven must not require successive bytes of data to be transferred to the microprocessor in less than 30 or 40 cycles and on a given system, only one device is capable of operating at that rate at one time. This limits the interrupt driven frequency of data transfer co 40KHZ at a one megahertz clock system and 80KHZ on a two megahertz clock system. An even more serious problem is the timing delay when an interrupt has just started to be serviced. The interrupt mask is on and higher priority interrupts are blocked from service. In this case, the delay to the service can easily stretch out to 100 cycles before the interrupt mask is cleared. This is one of the reasons for clearing up the interrupt mask as soon as data is transferred. (The non-maskable interrupt which will be discussed later is one solution to this problem.) A second is to only use interrupts for systems that have adequate buffering and/or slower transfer rates. This does not imply that most microprocessor applications should not be primarily interrupt driven. The MCS650X interrupt system is designed to be very economical and easy to apply. It should be used for almost all control applications, other than when the throughput described is not sufficient to handle the particular problem. It should be remembered that at one megahertz the fast MCS650X is not really capable of handling problems with more than 50KHZ byte throughput for a sustained period of operation. It is also true that in most control applications, many of the signals occur at much slower rates or are bufferable so that the response time to a request for service is significantly longer than the 20 to 50 cycles that can normally be expected with a polling system. Because of this, it is expected that most applications will be quite satisfied using the polling technique described above. 9.8 FULLY VECTORED INTERRUPTS However, there are occasions where several high speed peripherals can be managed by the microprocessor if the user is willing to make the investment to attain a truly vectored interrupt. There is a second level of interrupt vectoring possible by just putting one high priority device on the non-maskable interrupt line. However, the case when multiple inputs are desired with both priority encoding and true vectoring, the MCS650X when combined with appropriate hardware has the ability in the first polling instruction to transfer control to appropriate interrupting device service software. The MCS6520 contains, in its two bytes of memory, an indirect pointer to the address of the subroutine in which resides the interrupt processing for the devices, which the priority encoder has selected. This gives an effective service time of approximately 24 cycles to a prioritized interrupt and is one of the primary applications of the jump indirect capability. 9.8.1 JMP Indirect This instruction establishes a new value for the program counter. It affects only the program counter in the microprocessor and affects no flags in the status register. JMP Indirect is a three byte instruction. In the JMP Indirect instruction, the second and third bytes of the instruction represent the indirect low and high bytes respectively of the memory location containing ADL. Once ADL is fetched, the program counter is incremented with the next memory location containing ADH. Example 9.6: Illustration of JMP Indirect Address Data External Internal Cycle Bus Bus Operation Operation 1 0100 OP CODE Fetch OP CODE Finish Previous Operation. Increment PC to 0101 2 0101 IAL Fetch IAL Interpret Instructions Increment PC to 102 3 0102 IAH Fetch IAH Store IAL 4 IAH, IAL ADL Fetch ADL Add 1 to IAL 5 IAH,IAL+1 ADH Fetch ADH Store ADL 6 ADH, ADL Next OP Fetch Next CODE OP CODE 9.9 INTERRUPT SUMMARY There is an interrupt request line (IRQ) that, when low, indicates one of the devices which are connected to the interrupt request line requires service. At the beginning of the interrupt service routine, the user should save, on the stack, whatever registers will be used in his interrupt processing routine. His program then goes through a polling sequence to determine the interrupting device by analyzing the status registers in the order of priority of service for the I/O devices. On finding a device which requires service, the data for that device should be read or written as soon as possible and the interrupt disable cleared so that the microprocessor can interrupt again to service lower priority devices. Devices with over 40KHz byte transfer, etc., and mixed devices with over 20KHz should not normally be run interrupt driven. All others should be run interrupt driven as it minimizes the service time and programming for interrupt I/O operations. 9.10 NON-MASKABLE INTERRUPT As is discussed, it is often desirable to have the ability to interrupt an interrupt with a high priority device which cannot afford to wait during the time interrupts are disabled. For this reason, the MCS650X has a second interrupt line, called a Non-Maskable Interrupt. The input characteristics of this line are different than the interrupt request line which senses it needs service when it remains low. The non-maskable input is an edge sensitive input which means that when the collector-or'd input transitions from high to low, the microprocessor sets an internal flag such that at the beginning of the next instruction, no matter what the status of the interrupt disable, the microprocessor performs the interrupt sequence shown in Example 9.2 except that the vector pointer put out in cycle 6 and 7 is FFFA and FFFB. This gives two effects of a non-maskable interrupt. First, no matter what the status of the interrupt disable, the non-maskable interrupt will interrupt at the beginning of the next instruction, therefore, the maximum response time to the vector point is 14 cycles. Secondly, the internal logic of the MCS650X is such that if an interrupt request and nonmaskable interrupt occur simultaneously or if the non-maskable interrupt occurs prior to the time that the vectors are selected, the microprocessor always assigns highest priority to the non-maskable interrupt. Therefore, the FFFA and FFFB vector are always taken if both interrupts are active at the time the vector is selected. Thus the non-maskable interrupt is always a higher priority fast response line, and can, in any given system be used to give priority to the high speed device. It is possible to connect multiple devices to the non-maskable interrupt line except for the fact that the non-maskable interrupt is edge sensitive. Therefore, the same logic that allows the IRQ to stay low until the status has been checked and the data transferred will keep the non-maskable interrupt line in a low state until such time as the first interrupt is serviced. If subsequent to the first interrupt of a non-maskable interrupt line occuring, a second device which is collector-ored would have turned on its status and collector-or'd output, the clearing of the first interrupt request would not cause the line to re-initialize itself to the high state and the microprocessor would ignore the second interrupt. Therefore, multiple lines connected to the non—maskable interrupt must be carefully serviced. In any case, NMI is always one free high priority vectored interrupt. By virtue of the fact that it goes to a different vector pointer, the microprocessor programmer can be guaranteed that in 17 cycles he can transfer data from the interrupting device on the non-maskable interrupt input. The IRQ and NMI are lines which, externally to the microprocessor, control the action to the microprocessor through an interrupt sequence. As is mentioned during the discussion on the start command, the restart cycle is a pseudo interrupt operation with a different vector being selected for reset which has priority over both interrupt and nonmaskable interrupt. Non-maskable interrupt has priority over interrupt. There is also a software technique which allows the user to simulate an interrupt with a microprocessor command, BRK. It is primarily used for causing the microprocessor to go to a halt condition or stop condition during program debugging. 9.11 BRK - BREAK COMMAND The break command causes the microprocessor to go through an interrupt sequence under program control. This means that the program counter of the second byte after the BRK is automatically stored on the stack along with the processor status at the beginning of the break instruction. The microprocessor then transfers control to the interrupt vector. Symbolic notation for break is PC + 2↓ (FFFE)→PCL (FFFF)→PCH. Other than changing the program counter, the break instruction changes no values in either the registers or the flags. The BRK is a single byte instruction and its addressing mode is Implied. As is indicated, the most typical use for the break instruction is during program debugging. When the user decides that the particular program is not operating correctly, he may decide to patch in the break instruction over some code that already exists and halt the program when it gets to that point. In order to minimize the hardware cost of the break which is applicable only for debugging, the microprocessor makes use of the interrupt vector point to allow the user to trap out that a break has occurred. In order to know whether the vector was fetched in response to an interrupt or in response to a BRK instruction, the B flag is stored on the stack, at stack pointer plus 1, containing a one in the break bit position, indicating the interrupt was caused by a BRK instruction. The B bit in the stack contains if it was caused by a normal IRQ. Therefore, the coding to analyze for this is as follows in Example 9.6. Example 9.7: Break-Interrupt Processing Cycles Bytes Check for A BRK Flag 4 1 PLA Load status register 3 1 PHA Restore onto Stack 2 2 AND # $ 10 Isolate B Flag 2 2 BNE BRKP Branch to Break Programming 11 6 | ↓ Normal Interrupt Processing This coding can be inserted any place in the interrupt processing routine. During debugging, if the user can afford the execution time, it should be placed immediately after the save routine. If not, it can be put at the end of the polling routine which gives a priority to the polling devices as far as servicing the interrupts. However, it should be noted that in order not to lose the break, the returns from all interrupts during debugging should go through an equivalent routine. Once the user has determined that the break is on, a second analysis and correction must be made. It does not operate in a normal manner of holding the program counter pointing at the next location in memory during the BRK instruction. Because of this, the value on the stack for the program counter is at the break instruction plus two. If the break had been patched over an instruction, this is usually of no significant consequence to the user. However, if it is desired to process the next byte after the break instruction, the use of decrement memory instructions in the stack must be used. It is recommended that the user normally takes care of patching programs with break by processing a full instruction prior to returning and then use jump returns. An interesting characteristic about the break instruction is that it's OP CODE is all zero's (0), therefore, BRK coding can be used to patch fusable link PROMS through a break to an E-ROM routine which inserts patch coding. An example of using the break to patch with is shown below: Example 9.8: Patching with a break utilizing PROM Old Code FC21 LDA FC22 05 FC23 21 FC24 Next OP CODE Patched FC21 BRK 00 Code FC22 05 FC23 21 FC24 Next OP CODE The interrupt vector routine points to: Patch LDA 06 21 JMP 24 FC This coding substitutes: LDA 2106 for the LDA 2105 coding at FC21 by use of the BEK and a break processing routine. 9.12 MEMORY MAP A series of requirements were discussed to this point for the memory organization which can be illustrated by the following memory map: Hex Address 0000-00FF RAM used for zero page and indirect memory addressing operation. 0100-01FF RAM used for stack processing and for absolute addressing. 0200-3FFF Normally RAM. 4000-7FFF Normally I/O 8000-FFF9 Program storage normally ROM. FFFA Vector low address for NMI. FFFB Vector high address for NMI. FFFC Vector low address for RESET. FFFD Vector high address for RESET. FFFE Vector low address for IRQ + BRK. FFFF Vector high address for IRQ + BRK. The addressing schemes for I/O control between locations 4000 and 8000 Hex, have not been fully developed. This is described in detail in the Hardware Manual, Chapter 2. The Zero Page addressing requires that RAM should be located starting in location 00. If more than one RAM page is necessary, RAM location 0100 through 01FF should be reserved for the stack or at least a portion of parts should be reserved for the stack with the rest of it being available to the user to use as normal RAM. Locations from 0200 up to 4000 are normally reserved for RAM expansion. In small memory configurations such as are inherent in a MCS6530 class device, in order to minimize the addressing lines, page two (02XX) will be normally used for input/output as opposed to using the 40XX page which is used for devices which require significant amount of outboard RAM, ROM and I/O. Because of the fact that the MCS650X has three very important vector points selected in highest order memory, it is usually more useful to write programs with the memory storage located at a starting address which allows the programmer to make sure that the last address in his ROM contains the start and interrupt vectors. Because of these allocations, the user finds himself working in three directions. RAM is assigned in location 0000 working up. I/O devices are started at location 4000 starting up and ROM starts at location FFFF and works down. Although this seems like an unusual concept, one must remember that the hardware really only gives performance to either end of memory and, therefore, data located in the middle has no priority one over the other. So starting at either end is just as useful a technique as starting at one end and working up. In order to take maximum advantage of the capability of the microprocessor, particularly when using a symbolic assembler, working data should be located starting in the location 0, and stack addresses should be reserved until after analysis of the working storage requirements have been completed. Program storage should start in high order memory with some guess as to the amount of memory required being taken and that being taken as a start address. However, care should be taken to assign the three fixed vectors almost immediately at least symbolically as they are all necessary for correct operation of the microprocessor.