Category : Files from Magazines
Archive   : SNOOP.ZIP
Filename : MEMORY.ASM
Output of file : MEMORY.ASM contained in archive : SNOOP.ZIP
; *
; * Title: MEMORY.ASM
; * Copyright (c) October 1992, Ryu Consulting
; * Written by Rahner James
; *
; * This file contains the functions to support memory allocation functions
; *
; *************************************************************************************************
include ne2000.inc
MIN_PARAGRAPHS equ (200000/16) ; Number of paragraphs to allocate at first
.data
; *************************************************************************************************
; *
; * Global and Static
; *
; *************************************************************************************************
public Buffer_Start, Buffer_Size, Total_Allocated, First_Free, Last_MCB
Buffer_Start dw 0 ; Segment of the start of data
Buffer_Size dw 0 ; Number of paragraphs in the allocation pool
Total_Allocated dw 0 ; Number of paragraphs allocated
First_Free dw 0 ; Segment of the first free paragraph
Last_MCB dw 0 ; Segment of one past the last allocatable segment
.code
; *************************************************************************************************
; *
; * int INIT_MEMORY( void )
; * Initializes the memory buffer pool
; *
; * Given:
; * nothing
; *
; * Returns:
; * AX = 0 if all was initialized OKAY
; * AX = -1 if there is not enough data
; *
; *************************************************************************************************
init_memory proc uses bx cx di es
cld
cmp Buffer_Size, 0 ; See if already allocated
jz @F
mov ah, 49h ; AH = DOS Free Memory Block command
mov es, Buffer_Start
int 21h
mov Buffer_Size, 0
@@: mov ah, 48h ; AH = DOS Allocate Memory command
mov bx, MIN_PARAGRAPHS
int 21h
jnc @F
or ax, -1
jmp short done_init_memory
@@: mov Buffer_Start, ax
mov First_Free, ax
mov Last_MCB, ax
add Last_MCB, MIN_PARAGRAPHS
mov Buffer_Size, MIN_PARAGRAPHS
; *
; * Clear the entire buffer to 0's
; *
mov es, ax
mov cx, MIN_PARAGRAPHS
xor bx, bx
mov ax, bx
rept 4
add cx, cx
rcl bx, 1
endm
xor di, di
shr cx, 1
rep stosw
ifdef CPU286
shr di, 4
else
mov cl, 4
shr di, cl
endif
mov cx, es ; ES = next 64K
add cx, di
mov di, ax
@@: mov es, cx
mov cx, 8000h
rep stosw
mov cx, es
add cx, 1000h
dec bx ; One less 64K chunk
jnz @B ; Loop if we aren't done yet
; *
; * Now set up the first block
; *
mov es, Buffer_Start ; ES -> first memory chunk
mov cx, Buffer_Size
mov es:MCB_S.msize, cx ; Set the size of this block of memory
done_init_memory:
ret
init_memory endp
; *************************************************************************************************
; *
; * void FAR *ALLOC_NIC_ECB( ui CX )
; * Allocates an ECB from the memory pool
; *
; * Given:
; * CX = size of memory block to allocate, in bytes
; *
; * Returns:
; * ES:DI -> beginning of allocated memory block, NULL if error occurred
; * CARRY set if could not allocate a buffer of that size
; *
; * Note:
; * This algorthm seems to reach a crossover point at 63% of full where the average
; * buffer allocated is 1K. Empirically, when the average of the allocations reaches
; * 63% of the total memory pool, 1 NULL will occur out of 10,000. Above that point,
; * the number of NULLs will increase exponentially. (x^2)
; *
; *************************************************************************************************
alloc_NIC_ecb proc uses ax bx cx
pushf
or cx, cx
jz derr_alloc
add cx, 15+16 ; Round up to nearest number of paragraphs plus our MCB header
ifdef CPU286
shr cx, 4
else
rept 4
shr cx, 1
endm
endif
cli ; Protect from others
cmp First_Free, 0 ; See if there is any available
jz derr_alloc
mov es, First_Free ; ES -> first chunk of unallocated memory
@@: cmp es:MCB_S.msize, cx ; See if we can allocate this one
jnb alloc10 ; Jump if we can use this one
cmp es:MCB_S.next, 0 ; See if there is a next one
mov es, es:MCB_S.next ; ES = next segment anyway
jnz @B ; Loop if there is
jmp derr_alloc ; Here if there are fragments, but each one individually does not equal one whole chunk
; *
; * Here we dole out the memory buffer to the requester
; *
alloc10:
mov es:MCB_S.flags, MEM_ALLOC ; Set the memory block to allocated
mov ax, es ; AX = memory block segment
mov bx, ax ; BX = ditto
jz alloc40 ; Skip if we asked for an equal block to what's available
add ax, cx ; AX = next segment
cmp es:MCB_S.prev, 0 ; See if we are the first in the list
jnz alloc20 ; Skip if we aren't
mov First_Free, ax ; Set the first free
jmp short alloc30
alloc20:
mov es, es:MCB_S.prev ; Make the previous point at the new next
mov es:MCB_S.next, ax
mov es, bx
alloc30:
cmp es:MCB_S.next, 0 ; See if we are the last in the list
jz @F
mov es, es:MCB_S.next ; Make the next point back at the new previous
mov es:MCB_S.prev, ax
mov es, bx
@@: mov di, es:MCB_S.msize ; DI = size of this block of memory
mov es:MCB_S.msize, cx ; Make it the size we want
sub di, cx ; DI = size of the next memory block
mov cx, es:MCB_S.next ; CX -> the next one from this MCB
mov es:MCB_S.next, 0
push es:MCB_S.prev
mov es:MCB_S.prev, 0
mov es, ax ; ES -> next new chunk
mov es:MCB_S.next, cx
pop es:MCB_S.prev
mov es:MCB_S.msize, di
mov es:MCB_S.flags, MEM_FREE
mov es:MCB_S.under_chunk, bx
add di, ax ; DI -> next physical chunk
cmp di, Last_MCB ; See if we have gone over
jae alloc35 ; Skip if we have
mov es, di ; ES -> next physical chunk
mov es:MCB_S.under_chunk, ax
alloc35:
inc bx
mov es, bx ; ES:DI -> memory chunk allocated
inc Total_Allocated ; Number of packets allocated
xor di, di
jmp short done_alloc ; CARRY should be clear at this moment
; *
; * Here if the chunk requested is equal to the one we found
; *
alloc40:
mov ax, es:MCB_S.next ; AX = next free MCB
mov cx, es:MCB_S.prev
jcxz alloc50 ; Skip if we are at the beginning
mov es, cx ; Make the previous point at the new next
mov es:MCB_S.next, ax
mov es, bx
jmp short alloc60
alloc50:
mov First_Free, ax ; Set the first free
alloc60:
or ax, ax ; See if we are at the end of the list
jz alloc35 ; Loop if we are
mov es, ax ; ES = next MCB
mov es:MCB_S.prev, cx
jmp alloc35
derr_alloc:
xor di, di ; Return NULL
mov es, di
popf
stc
jmp short @F
done_alloc:
popf
@@: ret
alloc_NIC_ecb endp
; *************************************************************************************************
; *
; * int FREE_NIC_ECB( void FAR *ES:DI )
; * Frees a previously allocated ECB back to the memory pool
; *
; * Given:
; * ES:0 -> block to free
; *
; * Returns:
; * AX = 0 if all went well
; * CARRY set if there was a problem freeing the memory block
; *
; *************************************************************************************************
free_NIC_ecb proc uses bx cx di es
pushf
mov di, es ; Point ES (and DI) to the MCB
or di, di ; See if we were given NULL
jnz @F
free05:
jmp done10_merging ; Quit if we were
@@: mov di, es ; DI = segment given
dec di
mov es, di
cmp es:MCB_S.flags, MEM_FREE
jz free05
cli ; Disable interrupts
mov cx, First_Free ; AX -> old first in line of the free ones
mov es:MCB_S.next, cx ; Point us to them
jcxz @F ; Skip if it's NULL
mov es, cx
mov es:MCB_S.prev, di ; Make the old first in line point to us
mov es, di
@@: mov First_Free, di ; Point the first to us
mov cx, es:MCB_S.msize ; CX = size of our memory chunk
mov es:MCB_S.prev, 0
mov es:MCB_S.flags, MEM_FREE
; *
; * Now, loop doing the chunks after that, if there are any
; *
free10:
add cx, di ; CX -> next physical chunk
cmp Last_MCB, cx ; See if we have gone over the top
jbe free20 ; No need to go farther
mov es, cx ; ES -> next MCB
cmp es:MCB_S.flags, MEM_FREE
mov es:MCB_S.under_chunk, di
jne free20 ; Skip if not free
mov ax, es:MCB_S.next ; AX = next pointer
mov bx, es:MCB_S.prev ; BX = previous
mov cx, es:MCB_S.msize ; CX = size of this new chunk
or ax, ax ; See if that's the end of the line
jz @F
mov es, ax ; Make the next, point to this previous
mov es:MCB_S.prev, bx
@@: or bx, bx ; See if there is a previous chunk
jz @F ; Skip if not
mov es, bx
mov es:MCB_S.next, ax
@@: mov es, di ; ES -> our chunk
add es:MCB_S.msize, cx ; Make one big chunk
mov cx, es:MCB_S.msize
jmp free10
; *
; * Now, loop doing the chunks before that, if there are any
; *
free20:
mov es, di ; ES -> the first segment
cmp es:MCB_S.under_chunk, 0 ; See if we have a previous one
jz done_merging ; Quit if we don't
mov es, es:MCB_S.under_chunk
cmp es:MCB_S.flags, MEM_FREE
jne done_merging ; Skip if not free
; *
; * Disconnect from the linked list
; *
mov First_Free, es ; First _Free -> our new superchunk
mov ax, es:MCB_S.next ; AX = next pointer
mov bx, es:MCB_S.prev ; BX = previous
or ax, ax ; See if that's the end of the line
jz @F
mov es, ax ; Make the next, point to this previous
mov es:MCB_S.prev, bx
@@: or bx, bx ; See if there is a previous chunk
jz @F ; Skip if not
mov es, bx
mov es:MCB_S.next, ax
@@: mov es, di ; ES -> our old chunk
mov ax, es:MCB_S.next ; AX = next pointer
mov cx, es:MCB_S.msize ; CX = size of this new chunk
mov di, First_Free
mov es, di
mov es:MCB_S.next, ax
mov es:MCB_S.prev, 0
or ax, ax ; See if our old next is NULL
jz @F ; Skip if it is
mov es, ax
mov es:MCB_S.prev, di
mov es, di ; ES -> ourselves
; *
; * Make next physical chunk equal our own
; *
@@: add es:MCB_S.msize, cx ; New superchunk size
mov cx, es:MCB_S.msize ; CX = size of our chunk
add cx, di
cmp Last_MCB, cx ; See if we have gone over the top
jbe free20 ; Loop if we have
mov es, cx
mov es:MCB_S.under_chunk, di
jmp free20
; *
; * Merging is complete
; *
done_merging:
dec Total_Allocated ; One less allocated
done10_merging:
popf
xor ax, ax
ret
free_NIC_ecb endp
end
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/