Both the lowest-numbered physical addresses in memory and the highest-numbered physical address in memory are dedicated to interrupt and trap vectors in this architecture.
These trap vectors have the form:
Note that in addition to having a conventional value to load into the program counter, a second value is present for use if the interrupted process has a different register set from that used by the interrupt handler. This is because the additional information about the machine state that needs to be saved in this case will be different.
The locations used for interrupt vectors in the two cases will be:
0 ... 010000 - 011FFF F ... FC000 - FDFFF Supervisor Call (0 - 63) 0 ... 012080 - 012FFF F ... FE100 - FEFFF Interrupt (1 - 31) 0 ... 013000 - 01307F F ... FF000 - FF07F Illegal Operation 0 ... 013100 - 01317F F ... FF100 - FF17F Privilege Violation 0 ... 013200 - 01327F F ... FF200 - FF27F Read Access Violation 0 ... 013280 - 0132FF F ... FF280 - FF2FF Write Access Violation 0 ... 013300 - 01337F F ... FF300 - FF37F Execute Access Violation 0 ... 013380 - 0133FF F ... FF380 - FF3FF Page Fault 0 ... 013400 - 01347F F ... FF400 - FF47F Guarded Execution Mode Execute Violation 0 ... 013480 - 0134FF F ... FF480 - FF4FF Bounded Index Mode Execute Violation 0 ... 013800 - 01387F F ... FF800 - FF87F Test of Unordered Quantity 0 ... 013880 - 0138FF F ... FF880 - FF8FF Operation on Signaling NaN 0 ... 013900 - 01397F F ... FF900 - FF97F Standard Floating Invalid Operation 0 ... 013A80 - 013AFF F ... FFA80 - FFAFF Floating Underflow 0 ... 013B00 - 013B7F F ... FFB00 - FFB7F Inexact Arithmetic Result 0 ... 013B80 - 013BFF F ... FFB80 - FFBFF Inexact Conversion Result 0 ... 013C00 - 013C7F F ... FFC00 - FFC7F Divide by Zero 0 ... 013D00 - 013D7F F ... FFD00 - FFD7F Floating Overflow 0 ... 013D80 - 013DFF F ... FFD80 - FFDFF Fixed Overflow 0 ... 013E00 - 013E7F F ... FFE00 - FFE7F Conclude and Terminate executed (CP conclude) 0 ... 013E80 - 013EFF F ... FFE80 - FFEFF Conclude and Notify executed (CP complete) 0 ... 013F80 - 013FFF F ... FFF80 - FFFFF Power on
Note that a significant amount of space is reserved for future expansion of the architecture through defining additional trap conditions.
There is one exception, however, to the rule that the entire Program Status Block is replaced by the copy contained in the interrupt vector in use.
In the case of a supervisor call or a trap, but not in the case of a standard interrupt, the Register Map ID is replaced by the contents of the supervisor call alternate register map ID field, or the trap alternate register map ID field, of the former value of the Program Status Block respectively. This provides independent register space for traps and supervisor calls which are initiated from different processes.
In the case where a trap is initiated by a Conclude and Notify or Conclude and Terminate instruction, the new register map ID field is loaded from a control register within the long vector control circuitry itself; this control register is loaded, when a long vector ALU RISC MIMD cache-internal parallel computation is set up, from the field of the PSB containing the alternate register map ID for these traps; thus, the register map ID field is not loaded from this field of the PSB directly, so that the registers and storage used by the trap service routine depend not on the process running at the time of the trap, but on the process responsible for initiating the parallel computation.
This may be an appropriate place to note that, because the contents
of the Program Status Block are replaced during an interrupt, it contains
only those portions of the machine status that are local to a given
process. The status of an external I/O device is located in registers
within the device itself, or, in cases of devices closely tied to
the main computer, in control registers. These would contain such
information as the register map ID for the process currently being handled by
a long vector ALU RISC MIMD cache-internal parallel computation,
the status of external vector coprocessors, and the like.
An interrupt service routine is itself responsible for saving, through explicit instructions, and then restoring on exit, the contents of those of the machine's registers it intends to use. While this condition creates the potential for program errors which can cause serious difficulties, it is unavoidable because the architecture includes a large complement of registers, many of which are unlikely to be used by an interrupt service routine.
The overhead involved in saving and restoring registers is, however, also mitigated by the presence of register renaming in the architecture. An interrupt routine which has a register map ID giving it a unique allocation of register space, not shared with any other process, will not need to save or restore registers.
When this is not the case, the first order of business for an interrupt service routine will often be to save the contents of one or all of the base registers, so that it can perform a BRS instruction that will have the purpose of initializing the first base register it will use.
In addition to the return address, and a copy of the Program Status Block of the interrupted process, bytes C0 through EF of the machine state, having otherwise the same form as the interrupt vector as diagrammed above, will be used to contain information in a model-dependent format to permit resuming operation where a character string instruction, a Code 0 Microprogram, or other similar operation, is interrupted before completion.
This information can be used when a Return From Interrupt instruction is executed.
Since the interrupt vectors load the program status block and the program counters, the same information about the previously running process must be saved at the time of the interrupt, trap, or supervisor call.
This information, the fixed-length basic portion of the machine state, is two hundred and fifty-six bytes long and is in the following format in memory:
Interrupt routines are not, however, burdened with the task of saving this information. An interrupt service routine may not necessarily be given a new Register Map ID, as the architecture is upwards-compatible with subset implementations with only one set of registers. But an interrupt service routine is always given a new Process ID.
Each process ID, from 1 to 255, is associated with an area in the first 64 kilobytes of memory where the status information shown above is saved when that process is not among those which are actively executing.
These areas are allocated as follows:
0 ... 00100 - 001FF Process 1 status 0 ... 00200 - 002FF Process 2 status ... 0 ... 0FF00 - 0FFFF Process 255 status
The Source Process ID field in the Program Status Block allows an interrupt service routine to access the Program Status Block of the process that was interrupted on its behalf, if any.
Presumably, interrupt service routines for hardware interrupts can make use of absolute addressing modes to save register contents prior to loading base registers. Their strict prioritization also means that hardware interrupt service routines do not need to be written using re-entrant code.
Since a supervisor call is made intentionally within the routine in which it occurs, although a supervisor call resembles an interrupt in that it may lead to an escalation of privilege, saving and restoring all register contents is not an absolute necessity in its case.
But code servicing a supervisor call may be interrupted; that interruption may come from a timer interrupt that passes control to another user program, and that user program may happen to issue the identical supervisor call. In this case, re-entrant code becomes an absolute necessity, and a mechanism must be in place to ensure that every return address is preserved. As the last instance called will not necessarily be the first to return, a stack will not be sufficient.
In general, a trap, if enabled, is used to allow supervisory code to terminate a user program, or an inner loop within a user program, when an error such as an overflow is produced in a calculation. In such a case, some loss of register contents can often be tolerated; but this is not invariably the case, as traps might be used to simulate a modification to how arithmetic is performed.
The traps which handle signals from a cache-internal parallel process, however, are more like hardware interrupts than like a typical trap, since it is intended that cache-internal parallel computations may continue while the main central processing unit has turned its attention to tasks other than the one which initiated the parallel computation.
The foregoing discussion on interrupts, however, describes interrupts in terms of the traditional machine model, where there is only one process running at a time, and thus the status of only one process needs to be saved and restored when an interrupt happens.
In the case of traps and supervisor calls, this is entirely reasonable. A particular process issues a supervisor call, a particular process attempts to divide a number by zero. The other processes, not being involved, do not need to be disturbed.
Note that this explains why, when a cache-internal MIMD operation traps on a conclude and notify or conclude and terminate instruction, the trap must be recognized as being associated with the process that initiated the parallel computation, not whatever process may happen to be running when the trap takes place.
But what about hardware interrupts? Doesn't a hardware interrupt need the attention of the whole machine?
Even in the case of a CCN/CCT trap, the whole idea of saving the register map ID from the parent process is because the "wrong" process may be the one interrupted. One can't wait for the right process; besides wasting time, the right process may not even be running.
Just what is going on here?
What is envisaged is this: the chip will include, in hardware, perhaps eight or sixteen instruction issuer units: the number would be related to how deep the pipeline is. As the Process ID field in the Program Status Block is eight bits long, as many as 255 instruction issuer units are potentially usable; as it is envisaged that the highest-performance implementations, however, will have 65 floating-point ALUs, 65 integer ALUs, plus a handful of other special purpose processing units, 64 or 128 issuers are likely to be a reasonable upper limit.
Each instruction issuer unit will contain its own Program Status Block register, its own program counter, its own aux program counter, as well as copies of the apparent Program Status Block and the parent-apparent Program Status Block for purposes of virtualization.
The instruction issuers that are active at any one time function in a round-robin fashion.
Even a hardware interrupt, because the service routine is only a single set of instructions, obtains the use of only one of the instruction issuers. Thus, initially only one process has to be pushed out of the way immediately to let it begin running.
The hardware interrupt routine, however, will be running in supervisor mode. If the hardware interrupt happens to be the "Help! Somebody tripped over the power cord of this computer, and you need to save the status of all the running processes!" interrupt, that service routine will have access to the privileged, and model-dependent, instructions that take control of all the instruction issuer units, tell them to save their status, and that remove them (or add them) to the current round-robin of pipeline access.
The supervisor call for spawning a new process would probably work by adding information about the new process to a list in memory; then, the hardware timer interrupt service routine would look at that list, see how many instruction issuers are currently running, and if some are idle, it would add requested processes to the current round-robin.
This is done in order that the circuitry for alternating between concurrent processes can operate at high speed; attempting, in hardware, to add a new thread when an interrupt occurs would increase the complexity of a unit which is required for every instruction.
When a given process is interrupted, the instructions for that process in the pipeline have to be either abandoned, allowed to run to completion, or allowed to run to a permitted stopping point in the case of some instructions, such as those which move a long string of values from one location in memory to another. Instructions for other processes are not disturbed.
It may be noted that, in the diagram above, space is reserved in the saved state of the process for three versions of the Program Status Block.
Under normal circumstances, only the first one is used, which indicates the actual Program Status Block which applies to the process whose status is saved.
However, there is a bit marked Virtual in the Program Status Block. The purpose of that bit, in the actual Program Status Block for a process, is to indicate the process is running in a virtual machine. This means that the process will perceive itself to be running with a different level of privilege than it actually has; the intent is that the parent process, when it receives a privilege violation interrupt caused by the child process, will, if the privilege violation is due to a privilege the child process was to have believed itself to have, simulate the privileged operation for the child process, and then return control to the child process.
This explains the reason for the field labelled Apparent Program Status Block. A process running in a virtual machine may execute an instruction to read the current value of the Program Status Block, and such an instruction must return what it is intended to see, not the actual program status block with the processes real privilege level.
What is the purpose of the field labelled Parent-apparent Program Status Block?
Given the presence of a virtual machine capability, it may happen that a process might believe itself to have, but not actually have, the privilege to create a virtual machine child process. This applies automatically to all virtual machine processes; only a process that is not a virtual machine process may have the privilege to create a virtual machine child process directly. In such a case, a child process would normally be created for it by its parent process.
And in this case, when a virtual machine process delegates some of the privileges it believes itself to have to the virtual machine child process it seeks to have created, it may be that it will have delegated a privilege that it does not in fact posess.
Thus, what happens when a virtual machine process that is itself a child of a virtual machine process attempts to perform an operation can be broken down into the following cases:
Note that when an architecture has been in existence for some time, a virtualization feature that only allows virtual machines compatible with the definition of the architecture prior to the addition of the virtualization feature can still be useful, and so it is not necessarily true that all computers capable of running a virtual machine operating system addressed this issue.
When a process is running on a virtual machine, the real Program Status Block for that process will have its Virtual bit set (and the apparent Program Status Block will not have that bit set); then, when a violation of privilege is detected, the apparent Program Status Block for the process will be inspected as well, by the parent process, to determine if the privileged instruction should be simulated, or treated as an error. This does not need to be done in hardware, but an apparent Program Status Block in hardware allows instructions to update and inspect the Program Status Block to be handled quickly, without the need to call the parent process to simulate them.
When the parent process of a process is itself running on a virtual machine, the real Program Status Block will have its Multi-Level Virtual bit set as well as its Virtual bit set. Then the parent-apparent Program Status Block will also be inspected on privilege-related interruptions. If a privilege violation takes place, but the parent-apparent Program Status Block indicates that the parent process of the process generating the interrupt believes that process to have sufficient privilege for the operation, the parent of the parent process will be considered as the destination of the interrupt. If the grandparent process also believes the parent process to have sufficient privilege to perform this operation (this situation can only arise when the parent process itself cannot perform the operation, otherwise it would have successfully delegated the privilege to its child), by examining the parent-apparent Program Status Block of the parent process, the grandparent process will also be skipped, and so on.
Supervisor calls and traps from a process will always be directed to its parent, and hardware interrupts, such as requests from input/output devices, will always be directed to the real operating system.
It may, of course, be that the operating system will always directly receive all interrupts and traps, and examine these copies of the Program Status Block through software, but there will at least be instructions for examining and altering the Program Status Block of a child process for which a parent-apparent Program Status Block in hardware will be useful.
However, this can also be done in software, provided that, at a minimum, the hardware will trap, for programs running in virtual mode, instructions to examine the Program Status Block. This architecture already provides for trapping attempts to change selected portions of the Program Status Block, which is also required. In the minimal case, all interrupts would go directly to the actual operating system, and then be passed downwards through the ancestors of the source process at the discretion of each one.