;;; -*- Mode:gate; Fonts:(HL12 HL12I HL12B CPTFONTB HL12BI HL12B HL12I ) -*- =Node: Storage Layout Definitions =Text: 3STORAGE LAYOUT DEFINITIONS* The following special variables have values which define the most important attributes of the way Lisp data structures are laid out in storage. In addition to the variables documented here, there are many others that are more specialized. They are not documented in this manual since they are in the 2system* package rather than the 2global* package. The variables whose names start with 2%%* are byte specifiers, intended to be used with subprimitives such as 2%p-ldb*. If you change the value of any of these variables, you will probably bring the machine to a crashing halt. 3%%q-cdr-code* 1Constant* The field of a memory word that contains the cdr-code. See 4(MANLISTSTR-1)Cdr-Coding*. 3%%q-data-type* 1Constant* The field of a memory word that contains the data-type code. See 4(PRIMOBJTYPE-1)Data Types*. 3%%q-pointer* 1Constant* The field of a memory word that contains the pointer address, or immediate data. 3%%q-pointer-within-page* 1Constant* The field of a memory word that contains the part of the address that lies within a single page. 3%%q-typed-pointer* 1Constant* The concatenation of the 2%%q-data-type* and 2%%q-pointer* fields. 3%%q-all-but-typed-pointer* 1Constant* This is now synonymous with 2%%q-cdr-code*, and therefore obsolete. 3%%q-all-but-pointer* 1Constant* The concatenation of all fields of a memory word except for 2%%q-pointer*. 3%%q-all-but-cdr-code* 1Constant* The concatenation of all fields of a memory word except for 2%%q-cdr-code*. 3%%q-high-half* 1Constant* 3%%q-low-half* 1Constant* The two halves of a memory word. These fields are only used in storing compiled code. 3cdr-normal* 1Constant* 3cdr-next* 1Constant* 3cdr-nil* 1Constant* 3cdr-error* 1Constant* The values of these four variables are the numeric values that go in the cdr-code field of a memory word. See 4(MANLISTSTR-1)Cdr-Coding* for the details of cdr-coding. =Node: Analyzing Structures =Text: 3ANALYZING STRUCTURES %find-structure-header* 1pointer* This subprimitive finds the structure into which 1pointer* points, by searching backward for a header. It is a basic low-level function used by such things as the garbage collector. 1pointer* is normally a locative, but its data-type is ignored. Note that it is illegal to point into an ``unboxed'' portion of a structure, for instance the middle of a numeric array. In structure space, the ``containing structure'' of a pointer is well-defined by system storage conventions. In list space, it is considered to be the contiguous, cdr-coded segment of list surrounding the location pointed to. If a cons of the list has been copied out by 2rplacd*, the contiguous list includes that pair and ends at that point. 3%find-structure-leader* 1pointer* This is identical to 2%find-structure-header*, except that if the structure is an array with a leader, this returns a locative pointer to the leader-header, rather than returning the array-pointer itself. Thus the result of 2%find-structure-leader* is always the lowest address in the structure. This is the one used internally by the garbage collector. 3%structure-boxed-size* 1object* Returns the number of ``boxed Q's'' in 1object*. This is the number of words at the front of the structure which contain normal Lisp objects. Some structures, for example FEFs and numeric arrays, contain additional ``unboxed Q's'' following their boxed Q's. Note that the boxed size of a PDL (either regular or special) does not include Q's above the current top of the PDL. Those locations are boxed, but their contents are considered garbage and are not protected by the garbage collector. 3%structure-total-size* 1object* Returns the total number of words occupied by the representation of 1object*, including boxed Q's, unboxed Q's, and garbage Q's off the ends of PDLs. =Node: Creating Objects =Text: 3CREATING OBJECTS %allocate-and-initialize* 1data-type* 1header-type* 1header* 1second-word* 1area* 1size* This is the subprimitive for creating most structured-type objects. 1area* is the area in which it is to be created, as a fixnum or a symbol. 1size* is the number of words to be allocated. The value returned points to the first word allocated and has data-type 1data-type*. Uninterruptibly, the words allocated are initialized so that storage conventions are preserved at all times. The first word, the header, is initialized to have 1header-type* in its data-type field and 1header* in its pointer field. The second word is initialized to 1second-word*. The remaining words are initialized to 2nil*. The cdr-codes of all words except the last are set to 2cdr-next*; the cdr-code of the last word is set to 2cdr-nil*. It is probably a bad idea to rely on this. 3%allocate-and-initialize-array* 1header* 1data-length* 1leader-length* 1area* 1size* This is the subprimitive for creating arrays, called only by 2make-array*. It is different from 2%allocate-and-initialize* because arrays have a more complicated header structure. The basic functions for creating list-type objects are 2cons* and 2make-list*; no special subprimitive is needed. Closures, entities, and select-methods are based on lists, but there is no primitive for creating them. To create one, create a list and then use 2%make-pointer* to change the data type from 2dtp-list* to the desired type. =Node: Copying Data =Text: 3COPYING DATA* 2%blt* and 2%blt-typed* are subprimitives for copying blocks of data, word aligned, from one place in memory to another with little or no type checking. 3%blt* 1from* 1to* 1count* 1increment* 3%blt-typed* 1from* 1to* 1count* 1increment* Copies 1count* words, separated by 1increment*. The word at address 1from* is moved to address 1to*, the word at address 1from2+*increment* is moved to address 1to2+*increment*, and so on until 1count* words have been moved. Only the pointer fields of 1from* and 1to* are significant; they may be locatives or even fixnums. If one of them must point to the unboxed data in the middle of a structure, you must make it a fixnum, and you must do so with interrupts disabled, or else garbage collection could move the structure after you have already created the fixnum. 2%blt-typed* assumes that each copied word contains a data type field and checks that field, interfacing suitably with the garbage collector if necessary. 2%blt* does not check the data type fields of the copied words. 2%blt* may be used on any data except boxed data containing pointers to storage, while 2%blt-typed* may be used on any boxed data. Both 2%blt* and 2%blt-typed* can be used validly on data which is formatted with data types (boxed) but whose contents never point to storage. This includes words whose contents are always fixnums or short floats, and also words which contain array headers, array leader headers, or FEF headers. Whether or not the machine is told to examine the data types of such data makes no difference since, on examining them, it would decide that nothing needed to be done. For unboxed data (data which is formatted not containing valid data type fields), such as the inside of a numeric array or the instruction words of a FEF, only 2%blt* may be used. If 2%blt-typed* were used, it would examine the data type fields of the data words, and probably halt due to an invalid data type code. For boxed data which may contain pointers, only 2%blt-typed* may be used. If 2%blt* were used, it would appear to work, but problems could appear mysteriously later because nothing would notice the presence of the pointer there. For example, the pointer might point to a bignum in the number consing area, and moving it in this way would fail to copy it into a nontemporary area. Then the pointer would become invalidated the next time the number consing area was emptied out. There could also be problems with lexical closures and with garbage collection. =Node: Returning Storage =Text: 3RETURNING STORAGE return-storage* 1object* This peculiar function attempts to return 1object* to free storage. If it is a displaced array, this returns the displaced array itself, not the data that the array points to. Currently 2return-storage* does nothing if the object is not at the end of its region, i.e. if it was not either the most recently allocated non-list object in its area, or the most recently allocated list in its area. If you still have any references to 1object* anywhere in the Lisp world after this function returns, the garbage collector can get a fatal error if it sees them. Since the form that calls this function must get the object from somewhere, it may not be clear how to legally call 2return-storage*. One of the only ways to do it is as follows: 3(defun func ()* 3 (let ((object (make-array 100)))* 3 ...* 3 (return-storage (prog1 object (setq object nil)))))* so that the variable 2object* does not refer to the object when 2return-storage* is called. Alternatively, you can free the object and get rid of all pointers to it while interrupts are turned off with 2without-interrupts*. You should only call this function if you know what you are doing; otherwise the garbage collector can get fatal errors. Be careful. =Node: Locking Subprimitive =Text: 3LOCKING SUBPRIMITIVE %store-conditional* 1pointer* 1old* 1new* This is the basic locking primitive. 1pointer* is a locative to a cell which is uninterruptibly read and written. If the contents of the cell is 2eq* to 1old*, then it is replaced by 1new* and 2t* is returned. Otherwise, 2nil* is returned and the contents of the cell are not changed. See also 2store-conditional*, a higher-level function which provides type checking (4(PROCESSES-1)Locks*). =Node: CADR IO-Device Subprimitives =Text: 3CADR I/O-DEVICE SUBPRIMITIVES* The CADR processor has a 32-bit memory bus called the Xbus. In addition to main memory and TV screen memory, most I/O device registers are on this bus. There is also a Unibus compatible with the PDP-11. A map of Xbus and Unibus addresses can be found in 2SYS: DOC; UNADDR TEXT*. 3%unibus-read* 1address* Returns as a fixnum the contents of the register at the specified Unibus address. You must specify a full 18-bit address. This is guaranteed to read the location only once. Since the Lisp Machine Unibus does not support byte operations, this always references a 16-bit word, and so 1address* should normally be an even number. 3%unibus-write* 1address* 1data* Writes the 16-bit number 1data* at the specified Unibus address, exactly once. 3%xbus-read* 1io-offset* Returns the contents of the register at the specified Xbus address. 1io-offset* is an offset into the I/O portion of Xbus physical address space. This is guaranteed to read the location exactly once. The returned value can be either a fixnum or a bignum. 3%xbus-write* 1io-offset* 1data* Writes 1data*, which can be a fixnum or a bignum, into the register at the specified Xbus address. 1io-offset* is an offset into the I/O portion of Xbus physical address space. This is guaranteed to write the location exactly once. 3sys:%xbus-write-sync* 1w-loc* 1w-data* 1delay* 1sync-loc* 1sync-mask* 1sync-value* Does 2(%xbus-write 1w-loc* 1w-data*)*, but first synchronizes to within about one microsecond of a certain condition. The synchronization is achieved by looping until 3(= (logand (%xbus-read 1sync-loc*) 1sync-mask*) 1sync-value*)* is false, then looping until it is true, then looping 1delay* times. Thus the write happens a specified delay after the leading edge of the synchronization condition. The number of microseconds of delay is roughly one third of 1delay*. This primitive is used to alter the color TV screen's color map during vertical retrace. =Node: Lambda IO-Device Subprimitives =Text: 3LAMBDA I/O-DEVICE SUBPRIMITIVES sys:%nubus-read* 1slot* 1byte-address* Returns the contents of a word read from the Nu bus. Addresses on the Nu bus are divided into an 8-bit slot number which identifies which physical board is being referenced and a 24-bit address within slot. The address is measured in bytes and therefore should be a multiple of 4. Which addresses are valid depends on the type of board plugged into the specified slot. If, for example, the board is a 512k main memory board, then the valid address range from 0 to 4 * (512k - 1). (Of course, main memory boards are normally accessed through the virtual memory mechanism.) 3sys:%nubus-write* 1slot* 1byte-address* 1word* Writes 1word* into a word of the Nu bus, whose address is specified by 1slot* and 1byte-address* as described above. 3sys:%nubus-physical-address* 1apparent-physical-page* The valid portions of the Nu bus address space are not contiguous. Each board is allocated 16m bytes of address space, but no memory board actually provides 16m bytes of memory. The Lisp Machine virtual memory system maps virtual addresses into a contiguous physical address space. On the Lambda, this contiguous address space is mapped a second time into the discontiguous Nu bus address space. Unlike the mapping of virtual addresses to physical ones, the second mapping is determined from the hardware configuration when the machine is booted and does not change during operation. This function performs exactly that mapping. The argument is a physical page number (a physical address divided by 2sys:page-size*). The argument is a "Nu bus page number"; multiplied by 2sys:page-size* and then by four, it yields the Nu bus byte address of the beginning of that physical page. See also 2sys:%physical-address*, 4(SUBPRIMITIVES-2)The Paging System*. =Node: Function-Calling Subprimitives =Text: 3FUNCTION-CALLING SUBPRIMITIVES* These subprimitives can be used (carefully!) to call a function with the number of arguments variable at run time. They only work in compiled code and are not defined in the interpreted Lisp environment. The preferred higher-level primitive is 2apply* (4(EVAL-4)Some Functions and Special Forms*). 3%open-call-block* 1function* 1n-adi-pairs* 1destination* Starts a call to 1function*. 1n-adi-pairs* is the number of pairs of additional information words already 2%push*'ed; normally this should be 20*. 1destination* is where to put the result; the useful values are 0 for the value to be ignored, 1 for the value to go onto the stack, 3 for the value to be the last argument to the previous open call block, and 2 for the value to be returned from this frame. 3%push* 1value* Pushes 1value* onto the stack. Use this to push the arguments. 3%activate-open-call-block* Causes the call to happen. 3%pop* Pops the top value off of the stack and returns it as its value. Use this to recover the result from a call made by 2%open-call-block* with a destination of 1. 3%assure-pdl-room* 1n-words* Call this before doing a sequence of 2%push*'s or 2%open-call-block*'s that will add 1n-words* to the current frame. This subprimitive checks that the frame will not exceed the maximum legal frame size, which is 255 words including all overhead. This limit is dictated by the way stack frames are linked together. If the frame is going to exceed the legal limit, 2%assure-pdl-room* signals an error. =Node: Special-Binding Subprimitive =Text: 3SPECIAL-BINDING SUBPRIMITIVE %bind* 1locative* 1value* 3bind* 1locative* 1value* Binds the cell pointed to by 1locative* to 1x*, in the caller's environment. This function is not defined in the interpreted Lisp environment; it only works from compiled code. Since it turns into an instruction, the ``caller's environment'' really means ``the binding block for the compiled function that executed the 2%bind* instruction''. The preferred higher-level primitives that turn into this are 2let* (4(EVAL-1)Variable Binding Constructs*), 2let-if* (4(EVAL-1)Variable Binding Constructs*), and 2progv* (4(EVAL-1)Variable Binding Constructs*). The binding is in effect for the scope of the innermost binding construct, such as 2prog* or 2let*--even one that binds no variables itself. 2%bind* is the preferred name; 2bind* is an older name which will eventually be eliminated. =Node: The Paging System =Text: 3THE PAGING SYSTEM* [Someday this may discuss how it works.] 3sys:%disk-switches* 1Variable* This variable contains bits that control various disk usage features. Bit 0 (the least significant bit) enables read-compares after disk read operations. This causes a considerable slowdown, so it is rarely used. Bit 1 enables read-compares after disk write operations. Bit 2 enables the multiple page swap-out feature. When this is enabled, as it is by default, each time a page is swapped out, up to 16. contiguous pages are also written out to the disk if they have been modified. This greatly improves swapping performance. Bit 3 controls the multiple page swap-in feature, which is also on by default. This feature causes pages to be swapped in in groups; each time a page is needed, several contiguous pages are swapped in in the same disk operation. The number of pages swapped in can be specified for each area using 2si:set-swap-recommendations-of-area*. 3si:set-swap-recommendations-of-area* 1area-number* 1recommendation* Specifies that pages of area 1area-number* should be swapped in in groups of 1recommendation* at a time. This recommendation is used only if the multiple page swap-in feature is enabled. Generally, the more memory a machine has, the higher the swap recommendations should be to get optimum performance. The recommendations are set automatically according to the memory size when the machine is booted. 3si:set-all-swap-recommendations* 1recommendation* Specifies the swap-in recommendation of all areas at once. 3si:wire-page* 1address* &optional 1(wire-p* 3t1)** If 1wire-p* is 2t*, the page containing 1address* is 1wired-down*; that is, it cannot be paged-out. If 1wire-p* is 2nil*, the page ceases to be wired-down. 3si:unwire-page* 1address* 2(si:unwire-page 1address*)* is the same as 2(si:wire-page 1address* nil)*. 3sys:page-in-structure* 1object* Makes sure that the storage that represents 1object* is in main memory. Any pages that have been swapped out to disk are read in, using as few disk operations as possible. Consecutive disk pages are transferred together, taking advantage of the full speed of the disk. If 1object* is large, this is much faster than bringing the pages in one at a time on demand. The storage occupied by 1object* is defined by the 2%find-structure-leader* and 2%structure-total-size* subprimitives. 3sys:page-in-array* 1array* &optional 1from* 1to* This is a version of 2sys:page-in-structure* that can bring in a portion of an array. 1from* and 1to* are lists of subscripts; if they are shorter than the dimensionality of 1array*, the remaining subscripts are assumed to be zero. 3sys:page-in-pixel-array* 1array* &optional 1from* 1to* Like 2sys:page-in-array* except that the lists 1from* and 1to*, if present, are assumed to have their subscripts in the order horizontal, vertical, regardless of which of those two is actually the first axis of the array. See 2make-pixel-array*, 4(ARRAYS-3)Order of Array Elements*. 3sys:page-in-words* 1address* 1n-words* Any pages that have been swapped out to disk in the range of address space starting at 1address* and continuing for 1n-words* are read in with as few disk operations as possible. 3sys:page-in-area* 1area-number* 3sys:page-in-region* 1region-number* All swapped-out pages of the specified region or area are brought into main memory. 3sys:page-out-structure* 1object* 3sys:page-out-array* 1array* &optional 1from* 1to* 3sys:page-out-pixel-array* 1array* &optional 1from* 1to* 3sys:page-out-words* 1address* 1n-words* 3sys:page-out-area* 1area-number* 3sys:page-out-region* 1region-number* These are similar to the above, except that they take pages out of main memory rather than bringing them in. Actually, they only mark the pages as having priority for replacement by others. Use these operations when you are done with a large object, to make the virtual memory system prefer reclaiming that object's memory over swapping something else out. 3sys:%page-status* 1virtual-address* If the page containing 1virtual-address* is swapped out, or if it is part of one of the low-numbered fixed areas, this returns 2nil*. Otherwise it returns the entire first word of the page hash table entry for the page. The 2%%pht1-* symbols in 2SYS: SYS; QCOM LISP* are byte specifiers you can use with 2%logldb* for decoding the value. 3sys:%change-page-status* 1virtual-address* 1swap-status* 1access-status-and-meta-bits* The page hash table entry for the page containing 1virtual-address* is found and altered as specified. 2t* is returned if it was found, 2nil* if it was not (presumably the page is swapped out). 1swap-status* and 1access-status-and-meta-bits* can be 2nil* if those fields are not to be changed. This doesn't make any error checks; you can really screw things up if you call it with the wrong arguments. 3sys:%compute-page-hash* 1virtual-address* Makes the hashing function for the page hash table available to the user. 3sys:%physical-address* 1virtual-address* Returns the physical address which 1virtual-address* currently maps into. The value is unpredictable if the virtual page is not swapped in; therefore, this function should be used on wired pages, or you should do 3(without-interrupts* 3 (%p-pointer virtual-address) ;2swap it in** 3 (sys:%physical-address virtual-address)) sys:%create-physical-page* 1physical-address* This is used when adjusting the size of real memory available to the machine. It adds an entry for the page frame at 1physical-address* to the page hash table, with virtual address -1, swap status flushable, and map status 120 (read only). This doesn't make error checks; you can really screw things up if you call it with the wrong arguments. 3sys:%delete-physical-page* 1physical-address* If there is a page in the page frame at 1physical-address*, it is swapped out and its entry is deleted from the page hash table, making that page frame unavailable for swapping in of pages in the future. This doesn't make error checks; you can really screw things up if you call it with the wrong arguments. 3sys:%disk-restore* 1high-16-bits* 1low-16-bits* Loads virtual memory from the partition named by the concatenation of the two 16-bit arguments, and starts executing it. The name 20* refers to the default load (the one the machine loads when it is started up). This is the primitive used by 2disk-restore* (see 4(MISCELL-3)Manipulating the Label*). 3sys:%disk-save* 1physical-mem-size* 1high-16-bits* 1low-16-bits* Copies virtual memory into the partition named by the concatenation of the two 16-bit arguments (20* means the default), then restarts the world, as if it had just been restored. The 1physical-mem-size* argument should come from 2%sys-com-memory-size* in 2system-communication-area*. If 1physical-mem-size* is negative, it is minus the memory size, and an incremental save is done. This is the primitive used by 2disk-save* (see 4(MISCELL-3)Updating Software*). 3si:set-memory-size* 1nwords* Specifies the size of physical memory in words. The Lisp machine determines the actual amount of physical memory when it is booted, but with this function you can tell it to use less memory than is actually present. This may be useful for comparing performance based on the amount of memory.