Dragon Cedar Runtime
ToFrom
DragonCore^.paRuss Atkinson
 PARC - CSL
SubjectDate
Dragon Cedar Runtime December 19, 1984
Path Name /Indigo/Dragon/Documentation/DragonCedarRuntime.tioga
Last editedby Russ Atkinson on December 19, 1984 11:31:24 pm PST
AbstractThis document describes the Cedar runtime support for the Dragon architecture.
Attributes technical, Cedar, Dragon
Dragon Cedar Runtime
Copyright © 1984 by Xerox Corporation. All rights reserved.
This document is a DRAFT, and most of the information in it is volatile. This document is also INCOMPLETE, and should be viewed with some suspicion. Revisions are currently being sent through Russ Atkinson.
Introduction
This document assumes familiarity with the Mesa programming language, the Cedar programming environment, and the following documents:
[Indigo]<Dragon>Documentation>DragonMesaChanges.tioga
[Indigo]<Dragon>Documentation>DragOps.tioga
In this document we present a sketch of the Cedar runtime support on the Dragon architecture.
Calls and Returns
This section gives tentative information about the strategy used for procedure calls and returns on Dragon. This section was originally derived from DragOps.tioga.
Simple call
The simple case of calling a procedure first pushes any arguments expected by the procedure, then calls the procedure via DFC or LFC. The first instruction is normally an ALS instruction, which sets L to the base of the arguments. Therefore, the arguments become the initial local variables without moving those arguments.
The return PC and the return L are pushed onto the IFU stack by the call. If there is insufficient room to do this, an IFU stack overflow trap is taken after the call has transferred control.
Global frames
If the procedure needs access to a global frame, then it is the responsibility of the procedure to setup a register with the pointer to the global frame. Current plans are to use the LGF instruction to load the global frame pointer from the global frame table into a local register. The LIQB instruction could be used to setup the global frame pointer in the case where there are few procedures for the frame, but space considerations will normally make it more desirable to use the 3-byte LGF instead of the 5-byte LIQB, since that will save 2 bytes per procedure.
Simple return
The simple case of returning from a procedure uses the RET opcode, which specifies how much to adjust the stack before returning. If the IFU stack is not empty, then the return PC and L are taken from the IFU stack, and the most recent entry in the IFU stack is discarded. If the IFU stack is empty when a RET is performed, the results are undefined. S is adjusted according to the alpha byte. For cases where the stack should not be adjusted on return the RETN opcode is used.
Procedure variables
For various reasons covered below, procedure variables are called with one more level of indirection than simple procedures. Procedure variables are implemented as pointers to words that contain the starting address of the procedure. To call through a procedure variable, the procedure variable is pushed, then a call is made to ([S])^ using SFCI. This convention leaves an extra word on the stack, so procedure variable calls must go to a different entry point than simple procedure calls.
Nested procedures
Nested procedures are implemented by placing the starting address in the local frame extension (the part of the local frame required to be in memory). The procedure variable for this nested procedure will be a pointer to this word. Therefore, on entry to the nested procedure, the address of the frame (plus an offset) will be on the stack, which makes computing the static link easy (a SUBB instruction).
Interface function call
Interface function calls are both more flexible and more involved than simple procedure calls. Interface records are referred to via positions in the global frame. Procedures exported through those interfaces have procedure variables in various slots of the interface record. To make an interface function call one simply sets up the arguments, fetches the procedure variable from the interface record, and performs a procedure variable call.
Multiple global frames
Although procedures must be specially compiled to use multiple global frames, there is no additional mechanism beyond forcing all calls to routines with multiple global frames to use the indirect procedure call. The address on top of the stack can then be used to find the global frame (probably via adding a constant). Support for multiple global frames can be delayed until there is need.
Coroutines
Coroutine calls are handled by traps. The data structures to be used are not yet defined. However, coroutine calls will be roughly as expensive as process switches. Support for coroutine can be delayed until there is need.
Processes and Scheduling
This section describes support for Mesa processes on Dragon. See [Ivy]<Atkinson>Dragon>DragonProcesses.mesa for more details.
<<not yet written>>
Safe Storage
This section describes Dragon specific changes to the Safe Storage facility of Cedar.
<<not yet written>>
How do we stop the world and trace the stack?
This is probably done by the emergency stop feature, which causes every processor to stop dead and save its state. Then we can trace the resident frames. There is some question about tracing the non-resident frame extensions, we can either make them resident (not too bad if they don't take too much space), or counted (yecch!), or have some way to stop all processes that manipulate REFs (complicated, but perhaps the best way, especially since high-priority service processes can run).
How do we support Lisp & Smalltalk?
(see [Ivy]<Atkinson>Dragon>DragonRC.mesa for more details)
Smalltalk can use the Cedar allocator and some predetermined range of type codes. Lisp can use the Cedar allocator for everything except CONS cells, which have to be special because they get used so much. References for CONS cells can be distinguished from other REFs by address range. We get fast tests by having CONS cells at the most negative end of the address space, and other REFs at the most positive (their slots can be reversed if desired). Small INTs and small exponent REALs (except for 0.0) can be fit into 32-bit numbers accoridng to the following scheme (using the top three address bits to distinguish).
0: +INT 4: CONS
1: +REAL 5: -REAL
2: +REAL 6: -REAL
3: REF 7: -INT
Smalltalk and Lisp get their own initial segments of type space (how much?), and can expand by using the Cedar type allocation facilities. The important part of the type game is that everyone has to deal with RC maps in the same way.
CONS cells occupy 9 bytes, 8 of them in the double word pointed to by the reference, and 1 byte in some predictable place in the same place. The odd byte holds the reference count.
Abstract machine
This section describes the primitives used by the Abstract Machine facility of Cedar.
<<not yet written>>
Source <-> Object mapping
<<not yet written>>
We eventually want to support making procedures out of common code and correctly reporting the source position. Also, we should support INLINEs. We will have to be careful about the distinction between context and continuation PCs.
Breakpoints
<<not yet written>>
We must provide a primitive interpreter here, since we cannot proceed the same way we do for the D-machines. It should also be possible to place a breakpoint on a conditional jump and only break on one sense of it!
Signals & Errors
This section describes the mechanism for handling signals and errors.
<<not yet written>>
must use general PC range to handler mapping to make everyone happy; this allows Interlisp & Smalltalk to use the same basic facility
Traps
This section gives tentative information about traps generated by the IFU. The general approach to traps is to have the instruction that generates the trap have no effect, and the return PC for the trap routine be the PC of the trapping instruction. Maskable traps (Reschedule, EU Stack overflow, and IFU stack overflow) disable further maskable traps until they are reenabled (usually via RETT). This section was originally derived from DragOps.tioga.
Reschedule
The reschedule trap occurs when the RESCHEDULE line is raised and interrupts are enabled. An attempt is made to have idle processors notice the RESCHEDULE line before non-idle processors (this is controlled by software). If the RESCHEDULE line is raised while interrupts are disabled, the reschedule trap will be deferred until interrupts are enabled again. The response to the reschedule trap is quite complex, and will not be covered in this note.
EU Stack overflow
The stack overflow trap occurs when an attempt to increase the EU stack pointer by 1 (S←S+1) would result in S crossing the stack overflow limit register (and traps are enabled). The limit, which is set by software, must allow sufficient room for the trap handler. The handler for this trap should migrate the eldest frame in the EU and IFU stack registers to memory, then return via RETT.
IFU stack overflow
The IFU stack overflow trap occurs when an attempt to call a procedure when the IFU stack is full (and stack overflow is enabled). Some number of IFU frames are still available after this trap occurs, so calls can be made by the trap handler. The handler for this trap is the same as for EU stack overflow.
Stack underflow
The stack underflow trap occurs when a return instruction (RET, RETN, or RETT) tries to return to an empty IFU stack. The trap handler must arrange to migrate a frame from memory to the IFU and EU registers. This is not a true trap, since the IFU stack is left empty on entry to the handler. When the transfer takes place, maskable traps are disabled.
ALU fault
The ALU fault trap occurs when the ALU detects integer overflow, a bounds check (due to the BNDCK instruction) or a NIL check (due to the NILCK instruction), or Lisp NaN. The handler for ALU fault should turn this trap into the appropriate error, depending on the instruction that raised the fault.
EU page fault
The EU page fault trap occurs when a reference to unmapped memory is made by the EU. The faulting address is available through a special EU register (MAR). The handler should determine if the page is valid, then either cause the page to be made present, or cause a page fault error. Interrupts are disabled during the trap handler.
IFU page fault
The IFU page fault trap occurs when a reference to unmapped memory is made by the IFU. The faulting address is available as the return PC. The handler should determine if the page is valid, then either cause the page to be made present, or cause a page fault error.
Instruction trap
Undefined instructions (also know as Xops) cause instruction traps. There is a separate instruction trap for each opcode. Some instructions are treated as defined in user mode, but not in kernel mode, and these instructions also cause instruction traps when executed in user mode.
To permit efficient emulation of extended instruction sets, all Xops behave as procedure calls to an address linearly dependent on the instruction code. Xops have different lengths, depending on the instruction code. Xops of length 2 push Alpha onto the stack (high-order bytes undefined), Xops of length 3 push AlphaBeta onto the stack (high-order bytes undefined), and Xops of length 5 push AlphaBetaGammaDelta.
For implementation reasons some undefined operations do not trap, but also do not produce well-defined results. These operations will be detailed when the PLA for the IFU is sufficiently determined.
Recent Changes
19 Dec 84
Started