pcs/squish.asm

753 lines
35 KiB
NASM
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

; =====> SQUISH.ASM
;***************************************
;* TIPC Scheme Runtime Support *
;* Memory Compaction Routines *
;* *
;* (C) Copyright 1985 by Texas *
;* Instruments Incorporated. *
;* All rights reserved. *
;* *
;* Date Written: 23 September 1985 *
;* Last Modification: 22 October 1985 *
;* *
;* rb 2/ 2/88 - put in TC's GC fix *
;* *
;***************************************
.286c ;; Utilize the expanded 80286 instruction set
include scheme.equ
DGROUP group data
XGROUP group PROGX
PGROUP group prog
MSDOS equ 021h
data segment word public 'DATA'
assume DS:DGROUP
ret_sav1 dw 0 ; return address save area
ret_sav2 dw 0 ; return address save area
;;;msg db " Compacting Memory *",0
;;;msg1a db "Moving List Cells",LF,0
;;;msg1b db "Moving Flonums",LF,0
;;;msg1c db "Moving Bignums",LF,0
;;;msg1d db "Moving Closures",LF,0
;;;msg1e db "Moving Code Blocks",LF,0
;;;msg1f db "Moving Vectors",LF,0
;;;msg1g db "Moving Continuations",LF,0
;;;msg1h db "Moving Symbols",LF,0
;;;msg1i db "Moving Strings",LF,0
;;;msg2 db "About to Relocate Pointers",LF,0
;;;msg3 db "Complementing GC Bits",LF,0
;;;msg4 db "About to Sweep",LF,0
data ends
prog segment byte public 'PROG'
assume CS:PGROUP
extrn %allocbl:far ; "alloc_block" linkage routine
;************************************************************************
;* Far Linkage to SUM_SPACE *
;************************************************************************
%sumspac proc far
pop ret_sav1
pop ret_sav2
extrn sum_spac:near
call sum_spac
push ret_sav2
push ret_sav1
ret
%sumspac endp
;************************************************************************
;* Far Linkage to GCSWEEP *
;************************************************************************
%gcsweep proc far
pop ret_sav1
pop ret_sav2
extrn gcsweep:near
call gcsweep
push ret_sav2
push ret_sav1
ret
%gcsweep endp
IFDEF EXPMEM
;************************************************************************
;* Far Linkage to GCCLEAN *
;************************************************************************
%gcclean proc far
pop ret_sav1
pop ret_sav2
extrn gcclean:near
call gcclean
push ret_sav2
push ret_sav1
ret
%gcclean endp
ENDIF
;************************************************************************
;* ***Temporary Long Linkage to PRINTF*** *
;************************************************************************
public %printf,%sdebug
%printf proc far
pop ret_sav1
pop ret_sav2
extrn printf:near
call printf
push ret_sav2
push ret_sav1
ret
%printf endp
;************************************************************************
;* ***Temporary Long Linkage to SDEBUG*** *
;************************************************************************
%sdebug proc far
pop ret_sav1
pop ret_sav2
extrn sdebug:near
call sdebug
push ret_sav2
push ret_sav1
ret
%sdebug endp
prog ends
PROGX segment byte public 'PROGX'
assume CS:XGROUP
extrn srelocat:near ; pointer relocation routine
extrn toggleGC:near ; complement GC bits
;************************************************************************
;* Garbage Collection -- Compaction Phase *
;************************************************************************
sq_args struc
sq_free dw NUMPAGES dup (?) ; amount of free space within each page
sq_plist dw NUMPAGES dup (?) ; list of pages
sq_BP dw ? ; caller's BP register
dw ? ; caller's ES register
dd ? ; return address (far call)
dw ? ; return address (near call)
sq_args ends
%squish proc far
push ES ; save caller's ES register
push BP ; and BP register
sub SP,offset sq_BP ; allocate local storage
mov BP,SP ; and establish addressability
; Compute the amount of free space in each page
lea BX,[BP].sq_free ; load address of size array
push BX ; and push as argument to "sum_space"
call %sumspac ; determine available space in each page
mov SP,BP ; drop argument from TIPC's stack
; Initialize table of page numbers
mov AX,DS ; make ES point to the data
mov ES,AX ; segment
mov CX,NUMPAGES ; load page count
lea DI,[BP].sq_plist ; load address of page number table
xor AX,AX ; initialize page number index to zero
pt_loop: stosw ; set page number to current position
add AX,WORDINCR ; increment page index
loop pt_loop ; process all page numbers
; Reset the similar page type chain headers
mov CX,NUMTYPES
mov AX,END_LIST
mov DI,offset pagelist
rep stosw
; Sort list of pages according to size available
mov DX,DEDPAGES*WORDINCR
sort_nxt: mov SI,DX
mov DI,[BP].sq_plist+[SI]
mov AX,[BP].sq_free+[DI] ; load amount of space in base page
sort_mor: add SI,WORDINCR ; increment inner loop index
mov DI,[BP].sq_plist+[SI] ; load page index
cmp AX,[BP].sq_free+[DI] ; has current page less space?
jbe sort_no ; if not, jump
mov AX,[BP].sq_free+[DI] ; load size of smaller free space
mov DI,DX
mov CX,[BP].sq_plist+[SI] ; exchange base page index
xchg CX,[BP].sq_plist+[DI] ; with current page
mov [BP].sq_plist+[SI],CX ; index
sort_no: cmp SI,NUMPAGES*WORDINCR-WORDINCR ; is inner loop complete?
jl sort_mor ; if not, jump
add DX,WORDINCR ; increment outer loop index
cmp DX,NUMPAGES*WORDINCR-WORDINCR ; is outer loop complete?
jl sort_nxt ; if not, keep on loopin'
; Update the similar page type chains
mov DI,DEDPAGES*WORDINCR
spt_loop: mov SI,[BP].sq_plist+[DI]
test attrib+[SI],NOMEMORY
jnz spt_end
mov BX,ptype+[SI]
mov AX,pagelist+[BX]
mov pagelink+[SI],AX
mov AX,SI
CORRPAGE AX
mov pagelist+[BX],AX
spt_end: add DI,WORDINCR
cmp DI,NUMPAGES*WORDINCR
jl spt_loop
IFDEF EXPMEM
call %gcclean ; Clean out Emm Page table for compaction
ENDIF
; Note: If printing messages, make ES point to the data segment
;;; mov AX,DS ;* Make ES point to the data
;;; mov ES,AX ;* segment
; Compact List Cells
;;; mov AX,offset msg1a ;*
;;; push AX ; * print message indicating we're
;;; call %printf ;* compacting list cells
call sq_list
; Compact Flonums
;;; mov AX,offset msg1b ;*
;;; push AX ; * print message indicating we're
;;; call %printf ;* compacting flonums
call sq_flo
; Compact Bignums
;;; mov AX,offset msg1c ;*
;;; push AX ; * print message indicating we're
;;; call %printf ;* compacting bignums
mov AX,BIGTYPE*2 ; load type code index for bignums
push AX ; and push as argument to "sq_var"
call sq_var
mov SP,BP ; drop arguments from stack
; Compact Closures
;;; mov AX,offset msg1d ;*
;;; push AX ; * print message indicating we're
;;; call %printf ;* compacting closures
mov AX,CLOSTYPE*2 ; load type code index for closures
push AX ; and push as argument to "sq_var"
call sq_var
mov SP,BP ; drop arguments from stack
; Compact Code Blocks
;;; mov AX,offset msg1e ;*
;;; push AX ; * print message indicating we're
;;; call %printf ;* compacting code blocks
mov AX,CODETYPE*2 ; load type index for code blocks
push AX ; and push as argument to "sq_var"
call sq_var
mov SP,BP ; drop arguments from stack
; Compact Vectors
;;; mov AX,offset msg1f ;*
;;; push AX ; * print message indicating we're
;;; call %printf ;* compacting vectors
mov AX,VECTTYPE*2 ; load type index for vectors
push AX ; and push as argument to "sq_var"
call sq_var
mov SP,BP ; drop arguments from stack
; Compact Continuations
;;; mov AX,offset msg1g ;*
;;; push AX ; * print message indicating we're
;;; call %printf ;* compacting continuations
mov AX,CONTTYPE*2 ; load type index for continuations
push AX ; and push as argument to "sq_var"
call sq_var
mov SP,BP ; drop arguments from stack
;;; Note: Let's not compact symbols for now. There are a few "special"
;;; symbols which mess things up in the runtime support if they
;;; move. Notably, CONSOLE_ and QUOTE_reg(?)
;;;; Compact Symbols
;;; mov AX,offset msg1h ;*
;;; push AX ; * print message indicating we're
;;; call %printf ;* compacting symbols
;;; mov AX,SYMTYPE*2 ; load type index for symbols
;;; push AX ; and push as argument to "sq_var"
;;; call sq_var
;;; mov SP,BP ; drop arguments from stack
; Compact Strings
;;; mov AX,offset msg1i ;*
;;; push AX ; * print message indicating we're
;;; call %printf ;* compacting strings
mov AX,STRTYPE*2 ; load type index for strings
push AX ; and push as argument to "sq_var"
call sq_var
mov SP,BP ; drop arguments from stack
; Relocate all moved pointers
;;; mov AX,offset msg2 ;*
;;; push AX ; * print a message that we're about
;;; call %printf ;* to perform pointer relocation
call srelocat ; relocate all pointers
; Toggle the GC bits used to denote forwarding
;;; mov AX,offset msg3 ;*
;;; push AX ; * print a message that we're
;;; call %printf ; * complementing the GC bits
call toggleGC ; complement the GC (forwarding) bits
IFDEF EXPMEM
call %gcclean ; Clean out Emm Page table
ENDIF
; Invoke the "sweep" portion of the garbage collector to reclaim memory
;;; mov AX,offset msg4 ;*
;;; push AX ; * print a message that it's
;;; call %printf ; * "sweep" time
call %gcsweep ; reclaim all freed memory
; Return to caller
mov SP,BP ; deallocate stack temporaries
add SP,offset sq_BP ; release local storage
pop BP ; restore caller's BP register
pop ES ; and ES register
ret ; return
%squish endp
;************************************************************************
;* Macro Support for List/Flonum Compaction *
;* *
;* Register usage during "move" phase of this routine: *
;* AX - backward chain header (destination page index) *
;* BX - (scratch register) *
;* CX - word count for block move *
;* DX - forward chain header (source page index) *
;* DS:[SI] - source list cell *
;* ES:[DI] - destination list cell *
;************************************************************************
sql_arg struc
sql_rev dw NUMPAGES dup (?) ; reversed linked list of list pages
sql_bptr dw ? ; reversed list header
sql_BP dw ? ; caller's BP
dw ? ; caller's ES
dw ? ; return address
sql_type dw ? ; type code index (for variable len objects)
sql_arg ends
sq_L_F macro uppercase,lowercase
local sql_go,sql_010,sql_020,sql_025,sql_030,sql_035
local sql_040,sql_050,sql_060,sql_070,sql_done,sql_ret
push ES ; save caller's ES
push BP ; save caller's BP
sub SP,offset sql_BP ; allocate local storage
mov BP,SP ; establish local addressability
; Create a reverse order linked list of pages
lea BX,[BP].sql_rev ; load addr of reverse linked list array
mov AX,uppercase&TYPE*2 ; load type code
pushm <AX,BX> ; push type code, array addr as arguments
call sq_rever ; create the reverse linked list
mov SP,BP ; drop arguments off TIPC's stack
cmp AX,END_LIST ; is list of pages empty?
jne sql_go ; if list non-empty, continue (jump)
jmp sql_ret ; if empty list, return
sql_go: ADJPAGE AX ; convert list header to page index value
; Move list cells from least dense pages to most dense pages
mov DX,lowercase&page ; load page number of least dense
ADJPAGE DX ; page and convert to page index
mov BX,DX ; copy page index into BX
push DS ; save DS register
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; * * * WARNING: The DS Register Doesn't Point to the Data Segment * * *
; * * * in the code which follows: * * *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
%LoadPage0 DS,BX ; load paragraph address of source page
mov SI,-uppercase&SIZE ; load source page index
jmp short sql_020 ; jump
; Follow backward chain to get new destination page
sql_010: mov BX,AX ; set next available cell address to
mov SS:nextcell+[BX],DI ; END_LIST
mov BX,BP ; calculate address of current element in
add BX,AX ; reversed page list
mov AX,SS:[BX].sql_rev ; load next page in backward chain
ADJPAGE AX ; convert page number to page index
sql_020: cmp AX,DX ; another destination page available?
jne sql_025
jmp sql_done ; if source page = destination page, jump
sql_025:
mov BX,AX ; copy destination page index to BX
%LoadPage1 ES,BX ; load paragraph address of dest page
mov DI,SS:nextcell+[BX] ; load free cell header
IFDEF EXTMEM
mov BX,DX ; reload dest. page so it won't ever
%LoadPage0 DS,BX ; get swapped out
ENDIF
; Make sure a cell is available in the destination page
sql_030: cmp DI,END_LIST
je sql_010
; Is there a cell to move from the source page?
sql_040: mov BX,DX
mov BX,SS:psize+[BX] ; load the page size and
sub BX,uppercase&SIZE ; compute end of page boundary
sql_050: add SI,uppercase&SIZE ; increment source page offset
cmp SI,BX ; end of source page?
ja sql_070 ; if end of page, jump
cmp [SI].car_page,0FFh ; is this cell referenced?
je sql_050 ; if an unreferenced cell, jump
; Move the cell from source page to destination page
sql_060: mov BX,ES:[DI].car ; load offset of next free cell in dest page
IF uppercase&SIZE - (uppercase&SIZE/2)*2
mov CX,uppercase&SIZE
rep movsb
ELSE
mov CX,uppercase&SIZE/WORDINCR ; load number of words to move
rep movsw ; copy the contents of the list cell
ENDIF
sub SI,uppercase&SIZE ; back up the source and destination
sub DI,uppercase&SIZE ; pointers
IFIDN <uppercase>,<LIST>
mov [SI].car_page,AL ; store a forwarding pointer into the car
mov [SI].car,DI ; field of the source list cell
ELSE
IFIDN <uppercase>,<FLO>
mov [SI].flo_data,AL
mov word ptr [SI].flo_data+1,DI
ELSE
OOPS invalid data type: uppercase
ENDIF
ENDIF
or byte ptr [SI].&lowercase&_gc,GC_BIT ; set GC bit to indicate
; forward
mov DI,BX ; copy next free cell offset into DI
jmp sql_030 ; process next move
; Follow forward pointer to get a next source page
sql_070: mov BX,DX ; copy forward chain header to BX
mov DX,SS:pagelink+[BX] ; load next page in forward chain
ADJPAGE DX ; convert page number to page index
mov BX,DX
%LoadPage0 DS,BX ; load paragraph address of source page
IFDEF EXTMEM
mov BX,AX ; reload dest. page so it won't ever
%LoadPage1 ES,BX ; get swapped out
ENDIF
mov SI,-uppercase&SIZE ; initialize source page index
cmp AX,DX ; does source page = destination page?
je sql_035
jmp sql_040 ; if not, keep on moving cells (jump)
sql_035:
; No more cells to move-- update destination page available cell header
mov BX,AX ; update next available cell pointer
mov SS:nextcell+[BX],DI ; in the destination page
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; * * * WARNING: The DS Register Doesn't Point to the Data Segment * * *
; * * * in the code above * * *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Copying complete
sql_done: pop DS ; restore data segment register (DS)
sql_ret: mov SP,BP ; clean up TIPC's stack
add SP,offset sql_BP ; deallocate local storage
pop BP ; restore caller's BP
pop ES ; restore caller's ES
ret ; return to caller
endm
;************************************************************************
;* List Cell Compaction *
;************************************************************************
sq_list proc near
sq_L_F LIST,list
sq_list endp
;************************************************************************
;* Flonum Compaction *
;************************************************************************
sq_flo proc near
sq_L_F FLO,flo
sq_flo endp
;************************************************************************
;* Variable Length Object Compaction *
;* *
;* Register usage during "move" phase of this routine: *
;* AX - backward chain header (destination page index) *
;* BX - (scratch register) *
;* CX - word count for block move *
;* DX - forward chain header (source page index) *
;* DS:[SI] - source list cell *
;* ES:[DI] - destination list cell *
;* *
;* Notes: *
;* *
;* 1. Any object which is less than 6 bytes in length cannot be moved *
;* because there's no place to put a forwarding pointer. If a *
;* page is encountered with such an object (e.g., a zero length *
;* vector) that object, and the remaining objects in that page are *
;* not copied. Processing continues with the next source page. *
;* *
;* 2. The current code block cannot be relocated, since the offset *
;* into the current code block is held in register SI in most of *
;* the code of the Scheme Virtual Machine emulator. Since it is *
;* not possible to update this offset, the page containing the *
;* current code block is skipped, if encountered during *
;* compaction. *
;************************************************************************
sq_var proc near
push ES ; save caller's ES
push BP ; save caller's BP
sub SP,offset sql_BP ; allocate local storage
mov BP,SP ; establish local addressability
; Create a reverse order linked list of pages
lea BX,[BP].sql_rev ; load addr of reverse linked list array
pushm <[BP].sql_type,BX> ; push type code, array addr as arguments
call sq_rever ; create the reverse linked list
mov SP,BP ; drop arguments off TIPC's stack
cmp AX,END_LIST ; is list of pages empty?
jne sqv_020 ; if list non-empty, continue (jump)
sqv_010: jmp sqv_ret ; if empty list, return
sqv_020: ADJPAGE AX ; convert list header to page index value
mov [BP].sql_bptr,AX ; save destination list header
; Move list cells from least dense pages to most dense pages
mov BX,[BP].sql_type ; load type index for page type
mov DX,pagelist+[BX] ; load page number of least dense
ADJPAGE DX ; page and convert to page index
cmp AX,DX ; destination page available?
je sqv_010 ; if source page = destination page, jump
mov BX,DX ; copy page index into BX
push DS ; save DS register
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; * * * WARNING: The DS Register Doesn't Point to the Data Segment * * *
; * * * in the code which follows: * * *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
cmp DL,byte ptr CB_pag ; does page contain current code block?
je sqv_052 ; if so, skip it
IFDEF EXPMEM
cmp psize+[BX],MIN_PAGESIZE ; page size greater than minimum?
jne sqv_052
ENDIF
%LoadPage0 DS,BX ; load paragraph address of source page
;;; mov DS,pagetabl,[BX] ; load paragraph address of source page
xor SI,SI ; load source page index
; Is there an object to move from the source page?
sqv_040: mov BX,DX
mov BX,SS:psize+[BX] ; load the page size and
sub BX,BLK_OVHD ; compute end of page boundary
sqv_050: cmp SI,BX ; end of source page?
ja sqv_052 ; if end of page, jump
cmp [SI].car_page,FREETYPE ; is this object referenced?
jne sqv_060 ; if a referenced object, jump
add SI,[SI].vec_len
jmp sqv_050
sqv_052: jmp sqv_070 ; process next source page
; Find next possible destination page
sqv_054: mov BX,AX
add BX,BP
mov AX,SS:[BX].sql_rev
ADJPAGE AX
cmp AX,DX
jne sqv_061
jmp sqv_done
; Find a block into which to move the referenced object
sqv_060: mov CX,[SI].vec_len ; load length of object
cmp CX,0 ;;; check for small string
jge sqv_001
mov CX,BLK_OVHD+PTRSIZE ;;; get the right value
sqv_001: cmp CX,BLK_OVHD+PTRSIZE ; is object "too small" to relocate?
jae sqv001
jmp sqv_070 ; if "too small", abandon this page
sqv001: mov AX,[BP].sql_bptr ; load destination page list header
sqv_061: mov BX,AX ; copy index for destination page
IFDEF EXPMEM
cmp psize+[BX],MIN_PAGESIZE ; page size greater than minimum?
jne sqv_054
ENDIF
%LoadPage1 ES,BX ; load paragraph address of dest page
IFDEF EXTMEM
%LoadPage0 DS,DX ; reload src page so it won't get swapped out
ENDIF
xor DI,DI ; page and initialize its index pointer
mov BX,SS:psize+[BX] ; load page size and
sub BX,BLK_OVHD ; adjust for boundary check
jmp short sqv_064 ; jump over increment
sqv_062: cmp ES:[DI].vec_len,0 ;;; check for small string
jge sqv_002
add DI,BLK_OVHD+PTRSIZE ;;; add the exact length
jmp sqv_064
sqv_002: add DI,ES:[DI].vec_len ; advance destination page index
sqv_064: cmp DI,BX ; end of page?
ja sqv_054 ; if end of page, jump
cmp ES:[DI].vec_type,FREETYPE ; free block?
jne sqv_062 ; if not a free block, keep looking (jump)
; Free block found-- is it big enough?
cmp CX,ES:[DI].vec_len
ja sqv_062
je sqv_068 ; if an exact fit, jump
sub CX,ES:[DI].vec_len
neg CX
cmp CX,BLK_OVHD
jge sqv_066
mov CX,[SI].vec_len
cmp CX,0 ;;; check for small string
jge sqv_062
mov CX,BLK_OVHD+PTRSIZE ;;; get the right value
jmp sqv_062
sqv_066: cmp [SI].vec_len,0 ;;; check for small string
jge sqv_003
add DI,BLK_OVHD+PTRSIZE ;;; add the right value
jmp sqv_004
sqv_003: add DI,[SI].vec_len
sqv_004: mov ES:[DI].vec_type,FREETYPE
mov ES:[DI].vec_len,CX
mov CX,[SI].vec_len
cmp CX,0 ;;; check for small string
jge sqv_005
mov CX,BLK_OVHD+PTRSIZE
sqv_005: sub DI,CX
; Move the cell from source page to destination page
sqv_068: mov BX,CX ; save the number of bytes moved
rep movsb ; copy object from source page to dest page
sub SI,BX ; back up the source and destination
sub DI,BX ; pointers
mov [SI].vec_page,AL ; store a forwarding pointer into the car
mov [SI].vec_disp,DI ; field of the source object
or byte ptr [SI].vec_gc,GC_BIT ; set GC bit to indicate forward
add SI,BX ; advance source page index to next object
sqv_069: jmp sqv_040 ; process next move
; Follow forward pointer to get a next source page
sqv_070: mov BX,DX ; copy forward chain header to BX
mov DX,SS:pagelink+[BX] ; load next page in forward chain
ADJPAGE DX ; convert page number to page index
cmp AX,DX ; source = destination? ;rb for tc
je sqv_done ; yes, jump ;rb for tc
cmp DL,SS:byte ptr CB_pag ; current code block in this page?
je sqv_070 ; we can't relocate the current code block
mov BX,DX
IFDEF EXPMEM
cmp psize+[BX],MIN_PAGESIZE ; page size greater than minimum?
jne sqv_070
ENDIF
%LoadPage0 DS,BX ; load paragraph address of source page
IFDEF EXTMEM
%LoadPage1 ES,AX ; reload dest page so it won't get swapped
ENDIF
xor SI,SI ; initialize source page index
cmp AX,DX ; does source page = destination page?
jne sqv_069 ; if not, keep on moving objects (jump)
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; * * * WARNING: The DS Register Doesn't Point to the Data Segment * * *
; * * * in the code above * * *
; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Copying complete
sqv_done: pop DS ; restore data segment register (DS)
sqv_ret: mov SP,BP ; clean up TIPC's stack
add SP,offset sql_BP ; deallocate local storage
pop BP ; restore caller's BP
pop ES ; restore caller's ES
ret ; return to caller
sq_var endp
;************************************************************************
;* Local Support-- Create Reverse Linked List *
;* *
;* Purpose: To create a reversed copy of the similar page list for *
;* pages of a given type. *
;* *
;* Calling Sequence: header = sq_rever(dest_array, type_index) *
;* header = header pointer of reversed list. *
;* dest_array = array to hold the pointers of the reversed *
;* linked list. *
;* type_index = type index (type*2) of the page type for *
;* which the similar page linked list is *
;* to be reversed (e.g., LISTTYPE*2 causes *
;* the linked list for list cell pages to *
;* be reversed. *
;************************************************************************
sqr_args struc
dw ? ; caller's BP
dw ? ; return address
sqr_ary dw ? ; pointer to reversed list array
sqr_typ dw ? ; type code for desired page type
sqr_args ends
sq_rever proc near
push BP ; save caller's BP
mov BP,SP ; establish addressability
mov BX,[BP].sqr_ary ; load address of destination array
mov SI,[BP].sqr_typ ; load type code for list to reverse
mov SI,pagelist+[SI] ; load list header to appropriate page type
mov AX,END_LIST ; load an end of list indicator
sqr_loop: cmp SI,END_LIST ; end of list?
je sqr_ret ; if end of list, return
mov DX,SI ; save current page number in DX
ADJPAGE SI ; convert page number to page index
mov [BX]+[SI],AX ; store prev page number into reversed array
mov SI,pagelink+[SI] ; fetch next page in linked list
mov AX,DX ; prev page number <- current page number
jmp sqr_loop ; continue 'til end of list
sqr_ret: pop BP ; restore caller's BP
ret ; return with reversed list header in AX
sq_rever endp
PROGX ends
prog segment byte public 'PROG'
assume CS:PGROUP
;************************************************************************
;* Long Linkage to gcsquish *
;* *
;* Note: The lines which are commented out in the following code were *
;* used to print the "* compacting memory *" message in the *
;* who-line. Since it's a real pain in the a.. to allow the *
;* user to change the GC messages, it was decided that no *
;* message was the best way to go. *
;************************************************************************
public gcsquish
gcsquish proc near
push ES ; save caller's ES register
push BP ; save caller's BP register
mov BP,SP
mov AX,DS ; make sure ES points to the data segment
mov ES,AX
C_call gc_on ; light up the "garbage collecting" message
;;; mov AX,offset msg ; load address of compaction message
;;; push AX ; and push as argument
;;; C_call who_writ ; display "compacting memory" message
;;; mov SP,BP ; drop argument from stack
call %squish ; perform memory compaction
C_call gc_off ; reset the garbage collection message
pop BP ; restore caller's BP
pop ES ; restore caller's ES
ret ; return to caller
gcsquish endp
prog ends
end