pcs/sutil.asm

802 lines
28 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.

; =====> SUTIL.ASM
;***************************************
;* PC Scheme Runtime Support *
;* Misc Utilities *
;* *
;* (C) Copyright 1984.1985,1986 by *
;* Texas Instruments Incorporated. *
;* All rights reserved. *
;* *
;* Date Written: April 1984 *
;* Last Modification: 26 February 1986*
;***************************************
include scheme.equ
include pcmake.equ
;* Modification History:
;* 27 Jan 86 - Changed the code which looks for the TI Copyright notice
;* (JCJ) (when determining machine type) to search two areas instead
;* of just one. Now, checks are made at segment (paragraph)
;* offsets FC00 and FE00.
;*
;* 25 Feb 86 - Added the routine "put_ptr" to combine the "put_byte/put_word"
;* (JCJ) operations when a pointer is being stored into memory.
;*
;* 17 Feb 88 - Conditionally assemble XPCTYPE and PC_TYPE for Protected Memory
;* (TC) Scheme. These routines can be found in PRO2REAL.ASM and
;* REALIO.ASM for PROMEM
DGROUP group data
data segment word public 'DATA'
assume DS:DGROUP
extrn _base:word
data ends
IFNDEF PROMEM
; See PRO2REAL.ASM for protected mode scheme
XGROUP group PROGX
PROGX segment para public 'PROGX'
assume CS:XGROUP,DS:DGROUP
;************************************************************************
;* Determine PC's Manufacturer *
;* *
;* Purpose: To determine whether or not we're running on a TIPC or *
;* another brand and set the "PC_MAKE" variable accordingly. *
;* Returns: PC_MAKE will contain 1 for TIPC or Business Pro in TI mode*
;* FF for IBM-PC *
;* FE for IBM-PC/XT *
;* FD for IBM-PC/jr *
;* FC for IBM-PC/AT or B-P in IBM mode *
;* 0 for undeterminable *
;************************************************************************
public pc_type
XPCTYPE proc far
push ES ; save caller's ES register
push DI
mov AX,0FC00h ; move paragraph address of copyright
pc_002: mov ES,AX ; notice into ES
xor DI,DI ; Clear DI; 0 is lowest address in ROM @ES:
xor BX,BX ; Flag for "PC_MAKE" variable
mov CX,40h ; This'll be as far as I go...
mov AL,'T' ; look for beginning of "Texas Instruments"
cli ; Stop interrupts - bug in old 8088's
again:
repne scas byte ptr es:[di] ; SEARCH
or CX,CX ; Reach my limit?
jz short pc_005 ; quit if we've exhausted search
cmp byte ptr ES:[di],'e' ; make sure this is it
jne again ; use defaults if not found
cmp byte ptr ES:[di]+1,'x' ; really make sure this is it
jne again
push DS
mov DS,BX ; 0->DS for addressing low mem.
inc BX ; BX==1 => TIPC
mov AX,DS:word ptr [01A2h] ; If TIPC then what kind?
pop DS ; get DS back
add AL,AH ; checkout vector 68 bytes 2 & 3
cmp AL,0F0h ; if AL==F0 then TIPC=Business Pro
jne pc_010 ; jump if not a B-P
in AL,068h ; Read from port
push AX ; Save for later
and AL,0FBh ; Enable CMOS
out 068h,AL ; Write back out
mov DX,8296h ; I/O address for B-P's mode byte
in AL,DX ; TI or IBM Mode on the B-P?
cmp AL,0 ; if not zero then B-P emulates a TIPC
pop AX ; Restore original port value
out 068h,AL ; and write back out
jne pc_010 ; jump if TIPC else IBM machine code is
; where it should be.
jmp short pc_007
pc_005:
mov AX,ES
cmp AH,0FEh ; test for segment offset FE00
jae pc_007 ; two checks made? if so, jump
add AH,2 ; go back and check segment offset
jmp pc_002 ; FE00
pc_007: mov AX,0F000h
mov ES,AX
mov al,byte ptr ES:0FFFEh ; IBM's machine code is @F000:FFFE
cmp AL,IBMTYPE ; Is this suckah an IBM?
jb pc_010 ; Jump if AL is below F0 (BX will be 0)
mov BL,AL
pc_010: sti ; Turn interrups back on
mov PC_MAKE,BX ; set variable PC_MAKE
pop DI
pop ES ; restore caller's ES register
ret ; return to caller
XPCTYPE endp
PROGX ends
; See PRO2REAL.ASM for above definition
ENDIF
PGROUP group prog
prog segment byte public 'PROG'
assume CS:PGROUP
;For space and performance reasons, some procedures have been written in the
; following style: the arguments are popped off the stack, and the
; procedure ends in an indirect JMP instead of a RET. In this source file,
; the following are such procedures:
; zero_pag, zero_blk, get_byte, get_word, put_byte, put_word,
; get_flo, put_flo, get_str, put_str, get_sym, put_sym,
; make_ptr, alloc_fi, take_car, take_cdr
; Return Value of Stack Segment Register (SS:)
;;; public _SS
;;;_SS proc near
;;; mov AX,SS
;;; ret
;;;_SS endp
;;;; Return Value of Extra Segment Register (ES:)
;;; public _ES
;;;_ES proc near
;;; mov AX,ES
;;; ret
;;;_ES endp
;;;; Return Value of Code Segment Register (CS:)
;;; public _CS
;;;_CS proc near
;;; mov AX,CS
;;; ret
;;;_CS endp
; Return Value of Data Segment Register (DS:)
public _DS
_DS proc near
mov AX,DS
ret
_DS endp
; Zero a page in memory - Calling sequence: zero_page(page_no)
public zero_pag
zero_arg struc
dw ? ; Return address
zero_pg dw ? ; Page number
zero_arg ends
zero_pag proc near
pop DX ;Pop return address
pop BX ;Pop page number
push ES ;Save ES
sal BX,1
LoadPage ES,BX
;;; mov ES,DGROUP:pagetabl+[BX]
xor AX,AX
xor DI,DI
mov CX,psize+[BX]
shr CX,1
cld
rep stosw
pop ES ;Restore ES
jmp DX
zero_pag endp
;************************************************************************
;* Zero a block of memory *
;* *
;* Purpose: To initialize a variable length block of memory to zero. *
;* *
;* Description: The block is zeroed using the 8088's "store string" *
;* instruction using a repeat count. For *
;* efficiency reasons, the zeroing is done by *
;* words, with a fixup to account for blocks with *
;* an odd number of bytes. *
;* *
;* Calling sequence: zero_blk(page_no, disp) *
;* where page_no = page number (C's unshifted *
;* page number) *
;* disp = displacement of block within *
;* the page *
;************************************************************************
public zero_blk
zb_args struc
dw ? ; Return address
zb_page dw ? ; Page number
zb_disp dw ? ; Displacement
zb_args ends
zero_blk proc near
pop SI ;Pop return address
pop BX ; Pop the page number for the block
shl BX,1 ; and adjust for use as index
pop DI ; Pop the displacement of the block
push ES ; save the caller's ES register
LoadPage ES,BX
;;; mov ES,DGROUP:pagetabl+[BX] ; load page's paragraph address
mov CX,ES:[DI].vec_len ; and the block's length
add DI,BLK_OVHD ; and advance pointer past block header
cmp CX,0 ;;; check for small string
jge zero_010
add CX,PTRSIZE
jmp zero_020
zero_010: sub CX,BLK_OVHD ; subtract block overhead from the length
zero_020: mov DX,CX ; copy the length in bytes, and
and DX,1 ; isolate the least significant bit
shr CX,1 ; convert number of bytes to number of words
xor AX,AX ; load a value of zero into AX
cld ; set forward direction
rep stosw ; zero the block
mov CX,DX ; copy the fixup byte count
rep stosb ; zero the last byte, if odd number of bytes
pop ES ; restore ES register
jmp SI ; return to caller
zero_blk endp
; Fetch/Store byte/word
get_args struc ; Arguments Template
dw ? ; return address
get_page dw ? ; page number
get_disp dw ? ; displacement into page
get_val dw ? ; value (if a store operation)
get_args ends
; Get a byte of data
; Calling sequence: data = get_byte(page, disp)
; where: page ----- page number
; disp ----- (byte) displacement within page
public get_byte
get_byte proc near
mov CX,ES ; save caller's ES in CX
pop SI ; get return address
pop BX ; get page argument
shl BX,1 ; adjust it for segment lookup
LoadPage ES,BX
;;; mov ES,pagetabl+[BX] ; get page segment
pop BX ; get displacement
mov AL,ES:[BX] ; get byte
xor AH,AH ; and only a byte
mov ES,CX ; restore ES
jmp SI ; return
get_byte endp
; Get a word of data
; Calling sequence: data = get_word(page, disp)
; where: page ----- page number
; disp ----- (byte) displacement within page
public get_word
get_word proc near
mov CX,ES ; save caller's ES in CX
pop SI ; get return address
pop BX ; get page argument
shl BX,1 ; adjust it for segment lookup
LoadPage ES,BX
;;; mov ES,pagetabl+[BX] ; get page segment
pop BX ; get displacement
mov AX,ES:[BX] ; get word
mov ES,CX ; restore ES
jmp SI ; return
get_word endp
; Put a byte of data
; Calling sequence: put_byte(page, disp, value)
; where: page ----- page number
; disp ----- (byte) displacement within page
; value ---- value to be stored (low order 8 bits)
public put_byte
put_byte proc near
mov CX,ES ; save caller's ES in CX
pop SI ; get return address
pop BX ; get page
sal BX,1 ; double page number for use as index
LoadPage ES,BX
;;; mov ES,pagetabl+[BX] ; load page's paragraph address
pop BX ; get displacement
pop AX ; load byte to store
mov byte ptr ES:[BX],AL ; store new data
mov ES,CX ; restore segment register ES
jmp SI ; return
put_byte endp
; Put a word of data
; Calling sequence: put_word(page, disp, value)
; where: page ----- page number
; disp ----- (byte) displacement within page
; value ---- value to be stored (16 bits)
public put_word
put_word proc near
mov CX,ES ; save caller's ES in CX
pop SI ; get return address
pop BX ; load the page number
sal BX,1 ; double page number for use as index
LoadPage ES,BX
;;; mov ES,pagetabl+[BX] ; load page's paragraph address
pop BX ; load displacement
pop AX ; load word to store
mov word ptr ES:[BX],AX ; store new data
mov ES,CX ; restore segment register ES
jmp SI ; return
put_word endp
; Exchange a byte of data
; Calling sequence: old_data = xch_byte(page, disp, value)
; where: old_data - original data (overwritten)
; page ----- page number
; disp ----- (byte) displacement within page
; value ---- value to be stored (low order 8 bits)
; public xch_byte
;xch_byte proc near
; mov CX,ES ; save caller's ES in CX
; pop SI ; get return address
; pop BX ; get page
; sal BX,1 ; double page number for use as index
; mov ES,pagetabl+[BX] ; load page's paragraph address
; pop BX ; get displacement
; pop AX ; load byte to store
; xchg AL,byte ptr ES:[BX] ; swap old and new data
; xor AH,AH ; clear high order byte of AX
; mov ES,CX ; restore segment register ES
; jmp SI ; return
;xch_byte endp
; Exchange a word of data
; Calling sequence: old_data = xch_word(page, disp, value)
; where: old_data - original data (overwritten)
; page ----- page number
; disp ----- (byte) displacement within page
; value ---- value to be stored (16 bits)
; public xch_word
;xch_word proc near
; mov CX,ES ; save caller's ES in CX
; pop SI ; get return address
; pop BX ; load the page number
; sal BX,1 ; double page number for use as index
; mov ES,pagetabl+[BX] ; load page's paragraph address
; pop BX ; load displacement
; pop AX ; load word to store
; xchg AX,word ptr ES:[BX] ; swap old and new data
; mov ES,CX ; restore segment register ES
; jmp SI ; return
;xch_word endp
; Put a pointer
; Calling sequence: put_word(page, disp, pg_value, ds_value)
; where: old_data - original data (overwritten)
; page ----- page number
; disp ----- (byte) displacement within page
; pg_value ---- value of page number to store (16 bits)
; ds_value ---- value of displacement to store (16 bits)
public put_ptr
put_ptr proc near
mov CX,ES ; save caller's ES in CX
pop SI ; get return address
pop BX ; load the page number
sal BX,1 ; double page number for use as index
LoadPage ES,BX
;;; mov ES,pagetabl+[BX] ; load page's paragraph address
pop BX ; load displacement
pop AX ; load page number value to store
mov byte ptr ES:[BX],AL ; store page number
pop AX ; load displacement value to store
mov word ptr ES:[BX]+1,AX ; store page number
mov ES,CX ; restore segment register ES
jmp SI ; return
put_ptr endp
; Fetch/Store Flonum
getf_arg struc ; Arguments Template
dw ? ; caller's BP
dw ? ; return address
getf_pag dw ? ; page number
getf_dis dw ? ; displacement into page
getf_val dw ? ; value (if a store operation)
getf_arg ends
; Get a floating point value
; Calling sequence: fdata = get_flo(page, disp)
; where: page ----- page number
; disp ----- (byte) displacement within page
public get_flo
get_flo proc near
pop DI ;Pop return address
pop BX ; load the page number
sal BX,1 ; double page number for use as index
pop SI ; load displacement
inc SI ; and advance page flonum's tag
push DS ; save the caller's DS segment register
LoadPage DS,BX
;;; mov DS,pagetabl+[BX] ; load page's paragraph address
cld ;Direction forward
lodsw ;Put the flonum in AX:BX:CX:DX
mov DX,AX
lodsw
mov CX,AX
lodsw
mov BX,AX
lodsw
pop DS ; restore caller's DS segment register
jmp DI ; return
get_flo endp
; Put a flonum value into Scheme's memory
; Calling sequence: put_flo(page, disp, value)
; where: page ----- page number
; disp ----- (byte) displacement within page
; value ---- flonum value to be stored (4 words)
public put_flo
put_flo proc near
pop DX ;Pop return address
pop BX ; load the page number
sal BX,1 ; double page number for use as index
pop DI ; load displacement
inc DI ; and advance offset past flonum's tag
mov SI,SP ;SP points to flonum - point SI to it too
push ES ; save the caller's ES segment register
LoadPage ES,BX
;;; mov ES,pagetabl+[BX] ; load page's paragraph address
mov CX,FLOSIZE/WORDINCR ; load number of words to store
cld ; clear direction flag
rep movsw ; move the words of the flonum
pop ES ; restore the ES segment register
jmp DX ; return to caller
put_flo endp
; Transfer string to/from Scheme's memory
s_args struc
dw ? ; Caller's BP
dw ? ; Return address
sptr dw ? ; Pointer to string in C's memory
spage dw ? ; page number
sdisp dw ? ; displacement in page
lpage dw ? ; link field page number (for symbols)
ldisp dw ? ; link field displacement (for symbols)
hash_key dw ? ; hash value (for symbols)
s_args ends
public get_str,get_sym
get_str proc near
pop DX ;Pop return address
pop DI ; Fetch destination string's displacement
pop BX ; Fetch source page number
shl BX,1 ; Adjust page number for use as index
pop SI ; Fetch source string's displacement
push DS ;Save caller's DS
LoadPage DS,BX
;;; mov DS,pagetabl+[BX] ; Get source page's paragraph address
mov CX,[SI].vec_len ; Fetch length of string/symbol
add SI,offset vec_data ; Adjust for string header
cmp CX,0 ;;; check for small string
jge get_010
add CX,PTRSIZE
jmp get_mrg
get_010: sub CX,offset vec_data ; Adjust length for string header
get_mrg: cld ; clear string direction
rep movsb ; move 'em out
pop DS ; Restore DS segment register
jmp DX ;Return
get_str endp
get_sym proc near
pop DX ;Pop return address
pop DI ; Fetch destination string's displacement
pop BX ; Fetch source page number
shl BX,1 ; Adjust page number for use as index
pop SI ; Fetch source string's displacement
push DS ;Save caller's DS
LoadPage DS,BX
;;; mov DS,pagetabl+[BX] ; Get source page's paragraph address
mov CX,[SI].sym_len ; Fetch length of string/symbol
add SI,offset sym_data ; Adjust offset for symbol header
sub CX,offset sym_data ; Adjust length for symbol header
jmp get_mrg ;Get pname bytes
get_sym endp
public put_str,put_sym
put_str proc near
pop DX ;Pop return address
pop SI ; Load source string offset
pop BX ; Load destination page number,
pop DI ; and displacement
shl BX,1 ; Adjust page number for use as index
push ES ; Save caller's ES segment register
LoadPage ES,BX
;;; mov ES,pagetabl+[BX] ; Load destination page paragraph address
mov CX,ES:[DI].vec_len ; Load string length
add DI,offset vec_data ; Adjust pointer for string header
cmp CX,0 ;;; check for small string
jge put_010
add CX,PTRSIZE ;;; get the right string length
jmp putmrg
put_010: sub CX,offset vec_data ; Adjust length for string header
putmrg: cld ; Clear direction flag
rep movsb ; Move 'em in
pop ES ; Restore caller's ES
jmp DX ; Return
put_str endp
put_sym proc near
pop DX ;Pop return address
pop SI ; Load source string offset
pop BX ; Load destination page number,
pop DI ; and displacement
shl BX,1 ; Adjust page number for use as index
mov CX,ES ;Save caller's ES in CX
LoadPage ES,BX
;;; mov ES,pagetabl+[BX] ; Load destination page paragraph address
pop AX ; Load link field page number and
mov ES:[DI].sym_page,AL ; and move into symbol structure
pop ES:[DI].sym_disp ; Store link field displacement
pop AX ; move hash value into symbol data object
mov ES:[DI].sym_hkey,AL
push CX ;Now move caller's ES to stack
mov CX,ES:[DI].sym_len ; Load string length
add DI,offset sym_data ; Adjust displacement for symbol header
sub CX,offset sym_data ; Adjust length for symbol header
jmp putmrg ; Move 'em in
put_sym endp
; Convert page, displacement values to a long integer
public make_ptr
make_args struc
dw ? ; return address
mak_page dw ? ; page number
mak_disp dw ? ; pointer displacement
make_args ends
make_ptr proc near
pop DI
pop AX
adjpage AX
pop BX
jmp DI
make_ptr endp
; Allocate a cell for a fixnum (actually, return an immediate value)
; Calling sequence: alloc_fixnum(&reg, value)
a_fix_arg struc
dw ? ; Return address
a_reg dw ? ; Address of register to hold pointer
a_val dw ? ; Fixnum value
a_fix_arg ends
public alloc_fi
alloc_fi proc near
pop DI ;Pop return address
pop SI ; Pop address of return register
pop DX ; Pop fixnum value
sal DX,1 ; Shift out high order bit
jo a_fix_ov
a_fix_ov: ; Ignore overflow for now (create a bignum later)
shr DX,1 ; Position 15 bit quantity
mov [SI].C_disp,DX ; Store immediate value into register
mov [SI].C_page,SPECFIX*2 ; Store immediate tag
jmp DI ;Return
alloc_fi endp
;************************************************************************
;* Copy Variable Length Data Object *
;* *
;* Purpose: To create a copy of a variable length Scheme data object. *
;* *
;* Calling Sequence: copy_blk(&dest, &src) *
;* where &dest - address of VM register into which *
;* pointer to new copy is to be *
;* placed *
;* &src - address of VM register containing *
;* block to be copied *
;************************************************************************
cpy_args struc
dw ? ; caller's BP
dw ? ; caller's ES
dw ? ; return address
cpy_dest dw ? ; address of destination register
cpy_src dw ? ; address of source register
cpy_args ends
public copy_blk
copy_blk proc near
push ES ; save caller's ES
push BP ; save caller's BP
mov BP,SP
; allocate new block
mov SI,[BP].cpy_src ; load address of source register
mov BX,[SI].C_page ; load pointer to object to be copied
mov DI,[SI].C_disp
LoadPage ES,BX
;;; mov ES,pagetabl+[BX]
mov AX,ES:[DI].vec_len ; load length of object
cmp AX,0 ;;; check for small string
jge copy_010
add AX,PTRSIZE ;;; adjust for small string
jmp copy_011
copy_010: sub AX,BLK_OVHD ; adjust size for block header
copy_011: push AX ; push length of "data" in block
xor AX,AX ; load type field from source block
mov AL,ES:[DI].vec_type
push AX
push [BP].cpy_dest ; push address of destination register
mov AX,DS ; make ES point to the current data
mov ES,AX ; segment
C_call alloc_bl ; allocate new block
mov SP,BP ; drop arguments off stack
; copy contents of source block into newly created block
mov BX,[BP].cpy_dest ; make ES:[DI] point to newly created
mov DI,[BX].C_disp ; block
mov BX,[BX].C_page
LoadPage ES,BX
;;; mov ES,pagetabl+[BX]
mov BX,[BP].cpy_src ; make DS:[SI] point to source block
mov SI,[BX].C_disp
mov BX,[BX].C_page
push DS
LoadPage DS,BX
;;; mov DS,pagetabl+[BX]
mov CX,[SI].vec_len ; load length of source block
cmp CX,0 ;;; check for small string
jge copy_020
add CX,PTRSIZE
jmp copy_021
copy_020: sub CX,BLK_OVHD ; and subtract off size of block header
copy_021: mov DX,CX ; copy length (in bytes) into DX
and DX,1 ; and isolate the lsb
shr CX,1 ; convert size from bytes to words
add SI,BLK_OVHD ; advance source/destination pointers
add DI,BLK_OVHD ; past block header
rep movsw ; move contents of source to destination
mov CX,DX ; copy fixup (in case odd number of bytes)
rep movsb ; copy odd byte, if necessary
pop DS ; restore DS
; return to calling procedure
pop BP ; restore caller's BP
pop ES ; restore caller's ES
ret ; return
copy_blk endp
;;;; Make sure we haven't overflowed C's runtime stack
;;; public chk_stk
;;;chk_stk proc near
;;; mov AX,SP
;;; cmp AX,_base
;;; ja chk_ret
;;; C_call gc_on
;;; C_call exit
;;;chk_ret: ret
;;;chk_stk endp
;************************************************************************
;* C callable Routine to Take car/cdr of a List *
;************************************************************************
take_arg struc
dw ? ; caller's BP
dw ? ; return address
take_reg dw ? ; argument register address
take_arg ends
public take_car
take_car proc near
pop DX ;Pop return address
pop SI ; load argument register address
mov BX,[SI].C_page ; load list's page number
cmp byte ptr ptype+[BX],LISTTYPE*2 ; it is a list, isn't it?
jne take_err ; if not a list, error (jump)
mov CX,ES ; save caller's ES
LoadPage ES,BX
;;; mov ES,pagetabl+[BX] ; load list's page's paragraph address
mov BX,[SI].C_disp ; load list's offset
mov AL,ES:[BX].car_page ; copy car field of list cell
mov BX,ES:[BX].car
jmp short tkmrg
; ***error-- argument register doesn't contain list-- return nil***
take_err: mov [SI].C_page,NIL_PAGE*2
mov [SI].C_disp,NIL_DISP
jmp DX ; return
take_car endp
public take_cdr
take_cdr proc near
pop DX ;Pop return address
pop SI ; load argument register address
mov BX,[SI].C_page ; load list's page number
cmp byte ptr ptype+[BX],LISTTYPE*2 ; it is a list, isn't it?
jne take_err ; if not a list, error (jump)
mov CX,ES ; save caller's ES
LoadPage ES,BX
;;; mov ES,pagetabl+[BX] ; load list's page's paragraph address
mov BX,[SI].C_disp ; load list's offset
mov AL,ES:[BX].cdr_page ; Get cdr field of list cell
mov BX,ES:[BX].cdr
tkmrg: mov byte ptr [SI].C_page,AL ; Copy into argument register
mov [SI].C_disp,BX
mov ES,CX ; restore caller's ES
jmp DX ; return to caller
take_cdr endp
IFNDEF PROMEM
; See PRO2REAL.ASM for protected mode scheme
public pc_type
pc_type proc near
push BP
call XPCTYPE ; XPCTYPE is located at beginning of this
; program in XPROG, it determines PC type
pop BP
ret
pc_type endp
public pcinit
extrn XPCINIT:FAR
pcinit proc near
push BP
call XGROUP:XPCINIT ; XPCINIT is in GRAPHCMD.ASM - in XPROG
; it does special initialization per PC type
; also, it is called from main()
pop BP
ret
pcinit endp
; See PRO2REAL.ASM for above definitions
ENDIF
;************************************************************************
;* Symbol Hashing Routine *
;* *
;* Calling Seguence: hash_value = hash(symbol, len); *
;************************************************************************
public hash
hash proc near
pop DI ; unload return address
pop SI ; fetch symbol "string" pointer
pop CX ; fetch length
xor BX,BX ; zero accumulator
xor AH,AH
hash_1: lodsb ; fetch next character in symbol name
add BX,AX ; sum them up
loop hash_1 ; iterate 'til symbol used up
mov AX,BX ; copy sum of chars to AX
xor DX,DX
mov BX,HT_SIZE ; load divisor with hash table size
div BX ; divide sum
mov AX,DX
jmp DI ; return to caller
hash endp
;************************************************************************
;* Symbol Equality Routine *
;* *
;* Calling Sequence: equal? = sym_eq(page, disp, symbol, len); *
;************************************************************************
public sym_eq
sym_eq proc near
pop DX ; unload return address
pop BX ; fetch page number
shl BX,1 ; and adjust for word indexing
pop DI ; fetch displacement
pop SI ; fetch pointer to symbol name
pop CX ; fetch length
mov AX,ES ; save value of ES
LoadPage ES,BX
;;; mov ES,pagetabl+[BX] ; laod symbol page's paragraph address
mov BX,ES:[DI].sym_len ; fetch length of symbol
sub BX,offset sym_data ; and compute character count
cmp CX,BX ; length of symbol match?
jne not_eq ; if not same length, jump
add DI,offset sym_data ; advance symbol pointer to print name
repe cmpsb ; compare symbol to name
jne not_eq ; symbols the same? if not, jump
mov ES,AX ; restore caller's ES register
jmp DX ; return (non-zero value in AX => true)
not_eq: mov ES,AX ; restore caller's ES register
xor AX,AX ; zero AX (return false value)
jmp DX ; return
sym_eq endp
prog ends
end