pcs/expsmmu.asm

534 lines
14 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.

name EXPSMMU
title Scheme Memory Management Utilities for Expanded Memory
page 62,132
; =====> EXPSMMU.ASM
;****************************************************************
;* TIPC Scheme '84 Memory Management Utilities *
;* *
;* (C) Copyright 1985 by Texas Instruments Incorporated. *
;* All rights reserved. *
;* *
;* Author: Terry Caudill *
;* Date written: 18 March 1986 *
;* Modifications: *
;* tc 3/16/87 Better error handling for mapping errors and *
;* fix to requiring page frame on 64k boundary *
;* rb 4/5/87 "getbase" modified to return a page's swap *
;* status in the carry bit *
;****************************************************************
include schemed.equ
include schemed.ref
include schemed.mac
DOS equ 021h
EMM_DSR equ 67h ;; EMM DSR Interrupt
;; EMM DSR Function Requests
EMM_Status equ 40h ;; Get status of EMM
EMM_FrameAddr equ 41h ;; Get segment of page frame
EMM_PageCount equ 42h ;; How many pages available
EMM_Allocate equ 43h ;; Allocate pages
EMM_MapPage equ 44h ;; Map page into page frame
EMM_Dealloc equ 45h ;; Deallocate PCS'S expanded mem pages
DGROUP group data
PGROUP group prog
data segment word public 'DATA'
assume ds:DGROUP
extrn page0:byte, page4:byte, page5:byte, page6:byte
extrn page7:byte, page8:byte
extrn _top:word, _paras:word,first_pa:word,first_dos:word
Emm_Handle dw 0 ;; Handle returned by EMM
PageFrame dw 0 ;; Segment address for EMM Mapping
EmmAvail db 0 ;; Emm available
public FirstEmmPage
FirstEmmPage db 0 ;; First page number of Expanded Memory
public EmmPageNum,EmmPage,CodeIn
EmmPageNum db 2 ;; Emm Physical page number to map
EmmPage equ $
EmmPage0 db 0 ;; Table to map Emm Physical page
EmmPage1 db 0 ;; to actual pagetable offset
EmmPage2 db 0
CodeIn db 0 ;; Code block currently mapped
public GC_ING
GC_ING dw 0
EmmDeviceName db "EMMXXXX0"
m_ems_er db "[VM FATAL ERROR] Expanded Memory Manager error "
db 38h
p_errnum db 30h
db 0Ah,0
data ends
prog segment byte public 'PROG'
assume cs:PGROUP
public _MMU,_%MMU
public _%MMU0,_%MMU1,_MMUCB
public gcclean
public getbase
public InitMem
public rlsexp
extrn print_an:near ;; print_and_exit (truncated to 8 chars)
;;======================================================================
;;
;; _MMU - Take page passed on stack, and return its paragraph address
;; on the stack. If page in conventional memory, just get its
;; paragraph address from pagetabl. If in expanded memory and
;; already mapped in, return the PageFrame, otherwise request
;; the EMM to map the page into the PageFrame.
;;
;; NOTE: If an expanded memory page is requested which is greater
;; than the normal page size, Emm Pages 0 and 1 are loaded
;; automatically and address of page 0 returned.
;;
;;======================================================================
;**************************************************************************
; *
; W A R N I N G *
; Any references to data normally addressed by the data segment register *
; should be prefixed with SS: (segment override) because the DS register *
; may not contain the address of the current data segment. *
; *
;**************************************************************************
_MMU proc near ;; Normal Entry from PROG segment
push BP
mov BP,SP ;; Make stack accessable
push BX
mov BX,word ptr [bp+4] ;; BX <= Page number
cmp BL,SS:FirstEmmPage ;; Page in real memory?
jb _MMUPageRet0 ;; Yes..return
_MMU$0:
push AX ;; Save caller's regs
mov AX,2 ;; DX <= Emm Physical page #
cmp BL,SS:EmmPage2 ;; Mapped in Emm page 2?
je _MMU$00 ;; Yes ...jump
dec AX
cmp BL,SS:EmmPage1 ;; Mapped in Emm page 1?
je _MMU$00 ;; Yes ...jump
dec AX
cmp BL,SS:EmmPage0 ;; Mapped in Emm page 0?
jne _MMU$01 ;; Yes ...jump
_MMU$00:
mov SS:EmmPageNum,AL ;; Mark as last page mapped
jmp _MMUP$10
; If large page object, load 2 consecutive pages
_MMU$01:
cmp [SS:psize+BX],MIN_PAGESIZE ;; Normal sized page?
je _MMU$1 ;; Yes...jump
pop AX ;; Restore AX register
mov SS:EmmPageNum,0 ;; Map Page 0 with 1st page
push BX ;; Push Page number
call _MMUPage ;; Go map it
inc SS:EmmPageNum ;; Map Page 1 with 2nd page
add BX,2 ;; Get next page number
push BX ;; Push as argument
call _MMUPage ;; Go map it
pop BX ;; Ignore Para address of 2nd page
pop BX ;; Return Para address of 1st page
jmp _MMUPageRet
; Page not currently mapped - Lets map it
_MMU$1:
mov AL,SS:EmmPageNum ;; Last Emm physical page mapped
inc AL ;; Get next
cmp AL,3 ;;
jl _MMU$2 ;; If code block page
xor AL,AL ;; then wrap to zero
_MMU$2:
mov SS:EmmPageNum,AL ;; Update Emm Page last mapped
jmp _MMUP$1
_MMU endp
;;======================================================================
;;
;; _MMUPage - Load Expanded page number specified in EmmPageNum.
;; Emm Page 3 should only be used for the currently
;; executing code block (via LoadCode macro).
;;
;; NOTE: EmmPageNum must be set before this routine is called.
;;
;;======================================================================
_MMUPage proc near
push BP
mov BP,SP
push BX
mov BX,word ptr [bp+4] ;; Get page to map
cmp BL,SS:FirstEmmPage ;; Page in real memory?
jae _MMUP$0 ;; No...go map it
cmp SS:EmmPageNum,3 ;; Loading a code block?
jne _MMUPageRet0 ;; No...return page
mov SS:CodeIn,BL ;; Note code block
_MMUPageRet0:
mov BX,word ptr [BX+SS:pagetabl]
_MMUPageRet:
mov word ptr [bp+4],BX ;; return it
pop BX
pop BP
ret
_MMUP$0:
push AX
xor AH,AH
mov AL,SS:EmmPageNum ;; Get page number to map
_MMUP$1:
xchg AX,BX ;; Note page number in table
mov byte ptr [SS:EmmPage+BX],AL
xchg AX,BX
;; Map Page from Expanded memory
push AX ;; Save accross call
push DX
mov AH,EMM_MapPage ;; Map Page Function
sub BL,SS:FirstEmmPage ;; Convert page to map
shr BX,1 ;; to EMM Logical Page
mov DX,SS:Emm_Handle ;; EMM Handle
int EMM_DSR
pop DX ;; Restore saved regs
pop BX
or AH,AH ;; Error doing map page?
jnz Emm_Fatal_Map ;; Yes, fatal
mov AX,BX ;; restore AX
_MMUP$10:
mov BX,SS:PageFrame ;; Get current page frame
shl AL,1 ;; Convert to offset
shl AL,1
add BH,AL ;; and add to page frame
pop AX
jmp _MMUPageRet
Emm_Fatal_Map:
jmp Emm_Fatal_Error
_MMUPage endp
;;======================================================================
;;
;; Alternate Entry points
;;
;;======================================================================
;; Return Paragraph address of page number
_%MMU proc far ;; Entry from PROGX segment
push AX
call _MMU
pop AX
ret
_%MMU endp
;; Load Emm Page 0 - Called from garbage compactor
_%MMU0 proc far ;; Entry from PROGX segment
push AX
mov SS:EmmPageNum,0
call _MMUPAGE
pop AX
ret
_%MMU0 endp
;; Load Emm Page 1 - Called from garbage compactor
_%MMU1 proc far ;; Entry from PROGX segment
push AX
mov SS:EmmPageNum,1
call _MMUPAGE
pop AX
ret
_%MMU1 endp
;; Load Code Block into Emm Page 3 - Entry from PROG segment
_MMUCB proc near
mov SS:EmmPageNum,3
jmp _MMUPage
_MMUCB endp
;**************************************************************************
; *
; W A R N I N G *
; Any above references to data normally addressed by the data segment *
; register should be prefixed with SS: (segment override) because the *
; DS register may not contain the address of the current data segment. *
; *
;**************************************************************************
;;======================================================================
;;
;; Get page base address without forcing a page fault.
;; For debugging purposes only (SDUMP.C)....
;;
;; On exit, carry set if page is swapped out, else it's clear (used by XLI).
;;
;;======================================================================
getbase proc near
push BP
mov BP,SP
push BX
mov BX,word ptr [BP+4]
cmp BL,SS:FirstEmmPage
jae gc_00
mov AX,word ptr [BX+SS:pagetabl] ;; Get paragraph address
clc
jmp gb_quit
gc_00:
mov AX,2
cmp BL,SS:EmmPage0
je gb_5
dec AX
cmp BL,SS:EmmPage1
je gb_5
dec AX
cmp BL,SS:EmmPage2
je gb_5
dec AX
cmp BL,SS:CodeIn
stc
jne gb_quit
mov AX,3
gb_5:
shl AL,1
shl AL,1
or AL,byte ptr [SS:PageFrame+1]
xchg AL,AH
clc
gb_quit:
pop BX
pop BP
ret
getbase endp
;;======================================================================
;;
;; exppage()
;; This routine returns the first emm page number
;;
;;======================================================================
public exppage
exppage proc near
xor AH,AH
mov AL,FirstEmmPage
shr AL,1
ret
exppage endp
;;======================================================================
;;
;; gcclean()
;; This routine must be called after garbage collection and
;; compaction to clean up the pagetabl and EmmPage table.
;;
;;======================================================================
gcclean proc near
mov byte ptr EmmPageNum,0 ;; Reset EmmPage indicator
mov word ptr EmmPage,0
mov byte ptr EmmPage2,0
ret
gcclean endp
;;======================================================================
;;
;; InitMem()
;; Check to see if expanded memory manager is present and set up
;; the memory tables. Return the total number of pages (excluding
;; the dedicated ones) we've been able to allocate.
;;
;;======================================================================
Lcl_DS_Save dw data ;; Local copy of data segment
InitMem proc near
mov BX,DS
mov CS:Lcl_DS_Save,DS ;; Save DS for manager above
mov ES,BX ;; Ensure ES = DS
;; Convert offset within pagetabl[0] into paragraph address
mov DI,offset pagetabl
mov AX,word ptr [DI]
mov CX,4
shr AX,CL
add AX,BX
mov word ptr [DI],AX
;; Same for pagetabl[4] through pagetabl[8]
mov DX,5
mov DI,offset pagetabl[8]
EmmP$0:
mov AX,word ptr [DI]
shr AX,CL
add AX,BX
mov word ptr [DI],AX
add DI,2
dec DX
jnz EmmP$0
;; Compute first page paragraph address
;; (In the process, allocate all the memory that DOS will give us.)
mov BX,0FFFFh ;; first ask for too much
mov AH,048h
int DOS ;; DOS gets an error, but tells us
;; in BX how much we CAN get
mov AH,048h
int DOS ;; reissue allocation request
mov first_dos,AX ;; save address for returning it to DOS
add AX,(MIN_PAGESIZE shr 4) - 1 ;; Move to page boundary
and AX,not ((MIN_PAGESIZE shr 4) - 1)
mov first_pa,AX ;; first page paragraph address
;; Initialize page management table with pages available in real memory
mov DX,nextpage
mov freepage,DX ;; freepage = nextpage
mov DI,_paras ;; Get maximum number of paragraphs
sub DI,(MIN_PAGESIZE shr 4) ;; Get address of last paragraph
xor CX,CX ;; Keep number of pages in CX
EmmP$1:
cmp DI,AX ;; Did we reach it
jb EmmP$2 ;; Yes...no more
cmp DX,NUMPAGES ;; See if we have filled the table
jae EmmP$2
mov BX,DX
shl BX,1
mov word ptr [BX+pagetabl],AX
and word ptr [BX+attrib],not NOMEMORY
inc DX
mov word ptr [BX+pagelink],DX
mov word ptr [BX+nextcell],0
inc CX ;; page_count++
add AX,(MIN_PAGESIZE shr 4)
jmp EmmP$1
EmmP$2:
push CX ;; Save # real memory pages
shl DX,1
mov FirstEmmPage,DL ;; Save first exp mem page number
mov AH,35H ;; Get Interrupt Vector
mov AL,67H ;; "Vector"
int 21H
mov DI,000AH ;; ES:DI points to device name field
lea SI,EmmDeviceName ;; DS:SI points to device name
mov CX,8
cld
repe CMPSB ;; Compare the two strings
je EmmPres ;; Jump if EMM present
mov ES,CS:Lcl_DS_Save ;; Restore ES
xor BX,BX ;; No EMM pages available
jmp EmmP$2A ;; Skip talking to Emm Manager
EmmPres:
mov ES,CS:Lcl_DS_Save ;; Restore ES
mov AH,EMM_FrameAddr ;; Get Page Frame Address
int EMM_DSR
or AH,AH
jnz Emm_Fatal_Error
EmmP$:
mov PageFrame,BX ;; Save page frame address
mov AH,EMM_PageCount ;; Get Unallocated Pages Count
int EMM_DSR ;; (returned in BX)
or AH,AH
jnz EMM_Fatal_Error
EmmP$2A:
cmp BX,0 ;; Are there any pages available?
je EmmP$2B ;; No, jump
mov EmmAvail,1 ;; Yes, note pages available
EmmP$2B:
mov AX,BX ;; Number exp mem pages available
xor DX,DX
mov DL,FirstEmmPage ;; Restore first exp mem page
shr DX,1 ;; Convert to number
xor CX,CX ;; Page count
;; Why was this here? mov SI,PageFrame
EmmP$3:
cmp CX,AX ;; Last expanded memory page?
je EmmP$4 ;; Yes...no more
cmp DX,NUMPAGES ;; Filled the table?
jae EmmP$4 ;; Yes...no more
mov BX,DX
shl BX,1
mov word ptr [BX+pagetabl],0
and word ptr [BX+attrib],not NOMEMORY
inc DX
mov word ptr [BX+pagelink],DX
mov word ptr [BX+nextcell],0
inc CX
jmp EmmP$3
EmmP$4:
mov nextpage,DX ;; nextpage = lastpage
mov lastpage,DX ;;
jcxz EmmP$Ret ;; Return if no pages allocated
mov AH,EMM_Allocate ;; Allocate Pages
mov BX,CX ;; Number of pages
int EMM_DSR
or AH,AH
jnz Emm_Fatal_Error
mov emm_handle,DX ;; Save Handle returned
EmmP$Ret:
mov AX,CX ;; Get extended memory count
pop CX ;; Retrieve real memory count
add AX,CX ;; and return combination
ret
Emm_Fatal_Error:
mov BX,DS ;; Lattice needs ES=DS
mov ES,BX
and AH,0Fh ;; isolate low order nibble of error
add AH,'0' ;; convert to ascii
cmp AH,'9' ;; is it 0-9?
jbe Emm_Fat01 ;; yes, jump
add AH,'A'-'9'-1 ;; add fudge factor for A-F
Emm_Fat01:
mov byte ptr ss:p_errnum,AH ;; Set error indicator
lea BX,ss:m_ems_er ;; Fatal Error Message
push BX
C_call print_an
InitMem endp
;;======================================================================
;;
;; rlsexp - Release Expanded Memory Pages
;;
;;======================================================================
rlsexp proc near
cmp EmmAvail,0 ;; Emm being used?
je rlsret ;; No, Return
mov AH,EMM_Dealloc ;; Yes, Deallocate pages
mov DX,EMM_Handle
int EMM_DSR
rlsret:
ret
rlsexp endp
prog ends
end