Newer
Older
uBix-Retro / dump / oa-2.0.9 / oldlib / mem.a65
/****************************************************************************
   
    OS/A65 Version 2.0.0
    Multitasking Operating System for 6502 Computers

    Copyright (C) 1989-1998 Andre Fachat 

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

****************************************************************************/

/**********************************************************************
 * New memory management for IP buffers 
 * exports
 * 	binit
 * 	balloc, bfree, btrunc, bsplit, brealloc
 *	getbadr, getblen
 *
 * The routines are _not_ threadsave!
 * They have to be secured with SEM_MEM before calling them!
 *
 */

#define	IPBUFFER	$2000

#define	MINBUF	8
#define	MINMASK	%11111000

#ifndef MAXSLOT
#define	MAXSLOT	32
#endif

#ifndef MEMINIVAL
#define	MEMINIVAL 0
#endif

#undef DEBUGMEM
#undef DB
#define	DB(a)

	.(

	.data
slotladr .dsb MAXSLOT
slothadr .dsb MAXSLOT
slotllen .dsb MAXSLOT
slothlen .dsb MAXSLOT
slotrlln .dsb MAXSLOT
slotrhln .dsb MAXSLOT
slotownr .dsb MAXSLOT
slotpid  .dsb MAXSLOT

#ifdef NOMMU
init	.byt 0		; if not MEMINIVAL then init was ok!
#endif

flist 	.word 0
slot	.byt 0

	.zero
p	.word 0
p2	.word 0
p3	.word 0
p4	.word 0

;	.bss
;buf	.dsb IPBUFFER

	.text

/* init memory management */
/* x holds hibyte of start address of memory, y length in pages */
+binit	.(
#ifdef NOMMU
	lda init
	cmp #MEMINIVAL
	bne end
#endif
	stx flist+1
	stx p+1
	lda #0
	sta flist
	sta p

	tya
	ldy #3
	sta (p),y
	dey
	lda #0
	sta (p),y
	dey
	sta (p),y
	dey
	sta (p),y

	;lda #0
	tay
l0	sta slotladr,y
	sta slothadr,y
	sta slotownr,y
	iny
	cpy #MAXSLOT
	bcc l0

#ifdef NOMMU
	inc init
#endif
end
	clc
	rts
	.)

/**************************************************************************/
/* a/y = size of buffer to be allocated -> x buffer-ID */       
&balloc	.(
	/* walk along freelist, and take first matching buffer 
	   length is made a multiple of 8 (for freelist connectors */

	pha
	jsr getbslot
	pla
	bcc gotslot
	DB("balloc: no slot!^m^j")
	lda #E_NOMEM
	sec
	rts
gotslot
	stx slot

	sta slotrlln,x
	pha
	tya
	sta slotrhln,x
	pla

	adc #MINBUF-1
	and #MINMASK
	sta slotllen,x
	tya
	adc #0
	sta slothlen,x

	jsr GETPID
	txa
	ldx slot
	sta slotpid,x

/*jsr printlist*/
#if 0 /*def DEBUGMEM*/
DB("^m^jalloc(")
txa
jsr EHexout
lda slothlen,x
jsr EHexout
lda slotllen,x
jsr EHexout
DB("^m^jFlist=")
lda flist+1
jsr EHexout
lda flist
jsr EHexout
jsr ECrlfout
#endif	
	lda #0
	sta p2
	sta p2+1
	lda flist
	sta p
	lda flist+1
	sta p+1
l0
#if 0	/*def DEBUG*/
DB("^m^jCheck@")
lda p+1:jsr EHexout:lda p:jsr EHexout
jsr ECrlfout
#endif
	ldy #2
	lda (p),y
	sec
	sbc slotllen,x
	sta p3
	iny
	lda (p),y
	sbc slothlen,x
	sta p3+1
	bcs found 

	lda p
	sta p2
	lda p+1
	sta p2+1
	ldy #1
	lda (p2),y
	sta p+1
	dey
	lda (p2),y
	sta p
	ora p+1
	bne l0
	
oops	lda #E_NOMEM
	sec
	rts	

found
	/* ok, we found a free buffer: p points to the buffer, p2 to the
	   previous one. p3 is the length of the free buffer minus the
	   needed size. If the buffer is longer than needed, create a 
	   new free buffer, then link new buffer to freelist */

#if 0	/*def DEBUG*/
DB("Found Free buffer to alloc:")
DB("p=")
lda p+1:jsr EHexout:lda p:jsr EHexout
DB("p2=")
lda p2+1:jsr EHexout:lda p2:jsr EHexout
DB("p3=")
lda p3+1:jsr EHexout:lda p3:jsr EHexout
jsr ECrlfout
#endif

	lda p		/* save buffer address */
	sta slotladr,x
	lda p+1
	sta slothadr,x
	inc slotownr,x
		
	lda p3 		/* check length */
	ora p3+1
	beq nocreate
	
	lda p		/* get address of new free buffer */
	clc
	adc slotllen,x
	sta p4
	lda p+1
	adc slothlen,x
	sta p4+1

	ldy #0		/* copy next pointer */
	lda (p),y
	sta (p4),y
	iny
	lda (p),y
	sta (p4),y

	iny		/* set new length */
	lda slotllen,x
	sta (p),y
	lda p3
	sta (p4),y
	iny
	lda slothlen,x
	sta (p),y
	lda p3+1
	sta (p4),y
	jmp set2
nocreate
	ldy #0
	lda (p),y
	sta p4
	iny
	lda (p),y
	sta p4+1
set2
	lda p2
	ora p2+1
	beq freestart

	ldy #0
	lda p4
	sta (p2),y
	iny
	lda p4+1
	sta (p2),y
	clc
	bcc geta
freestart
#if 0	/*def DEBUG*/
DB("^m^jFreestart")
lda p+1:jsr EHexout:lda p:jsr EHexout:jsr ECrlfout
#endif
	lda p4
	sta flist
	lda p4+1
	sta flist+1
	clc
geta
#if 0 /*def DEBUGMEM*/
php:txa:pha
DB("^m^jallocated buffer ")
txa: jsr EHexout
lda slothadr,x: jsr EHexout: lda slotladr,x: jsr EHexout
lda slothlen,x: jsr EHexout: lda slotllen,x: jsr EHexout
jsr ECrlfout
jsr printmem
jsr printlist
pla:tax:plp
#endif
	lda slotladr,x
	ldy slothadr,x
	rts
	.)

/**************************************************************************/

/* free buffer (ID=xr) */
&bfree	.( 
/*clc:rts*/
&bfree2
	cpx #MAXSLOT
	bcc okfree
#if 0
	DB("bfree: illegal slot#, retadr=")
	txa:pha:tsx:lda $0103,x:jsr EHexout:lda $0102,x:jsr EHexout
	jsr ECrlfout:pla:tax
#endif
	sec
	rts
okfree	lda slotownr,x
	bne okf1
#if 0
	DB("bfree: slot ")
	txa:jsr EHexout:DB(" not in use, retadr=")
	txa:pha:tsx:lda $0103,x:jsr EHexout:lda $0102,x:jsr EHexout
	jsr ECrlfout:pla:tax
#endif
	sec
	rts
okf1
/*	DB("bfree(")*/

#if 0 /*def DEBUGMEM*/
DB("Freeing Slot ")
txa:jsr EHexout:DB(", #ownr="):lda slotownr,x:jsr EHexout:
DB(", retadr="):txa:pha:tsx:lda $103,x:jsr EHexout:lda $102,x:jsr EHexout
pla:tax:jsr ECrlfout
#endif

	dec slotownr,x
	bne end2

	lda slothadr,x
	sta p3+1
	lda slotladr,x
	sta p3
	ora p3+1
	beq end2

	ldy #2
	lda slotllen,x
	sta (p3),y
	iny
	lda slothlen,x
	sta (p3),y	

	lda #0
	sta slothadr,x
	sta slotladr,x

	lda flist
	ora flist+1
	bne ok		/* no free buffer so far? */

	lda p3
	sta flist
	lda p3+1
	sta flist+1
	ldy #0
	tya
	sta (p3),y
	iny
	sta (p3),y
end2	clc
	rts
ok	
	lda #0
	sta p2
	sta p2+1
	lda flist
	sta p
	lda flist+1
	sta p+1

	/* we have to find the place where to put the buffer in the
	   ordered free list. Then we have to check if we can merge
	   free buffers */
loop
#if 0	/*def DEBUGMEM*/
DB("Check slot ")
lda p+1: jsr EHexout:lda p: jsr EHexout
DB("["): ldy #3:lda (p),y:jsr EHexout:dey:lda (p),y:jsr EHexout
DB("]->"):ldy #1:lda (p),y:jsr EHexout:dey:lda (p),y:jsr EHexout
jsr ECrlfout
#endif

	lda p3+1
	cmp p+1
	bcc found
	bne next
	lda p3
	cmp p
	bcc found
next
	lda p
	sta p2
	lda p+1
	sta p2+1
	ldy #0
	lda (p2),y
	sta p
	iny
	lda (p2),y
	sta p+1
	ora p
	bne loop
	beq found
end
	clc
	rts

found	/* p2 is the buffer before the one to be freed, p the one behind.
	   p3 is the buffer to be inserted */

#if 0	/*def DEBUGMEM*/
DB("Found buffer^m^j")
DB("p3=")
lda p3+1:jsr EHexout:lda p3:jsr EHexout:jsr ECrlfout
DB("p2=")
lda p2+1:jsr EHexout:lda p2:jsr EHexout
DB("["):ldy #3:lda (p2),y:jsr EHexout:dey:lda (p2),y:jsr EHexout
DB("]->"):ldy #1:lda (p2),y:jsr EHexout:dey:lda (p2),y:jsr EHexout
jsr ECrlfout
DB("p=")
lda p+1:jsr EHexout:lda p:jsr EHexout
DB("["):ldy #3:lda (p),y:jsr EHexout:dey:lda (p),y:jsr EHexout
DB("]->"):ldy #1:lda (p),y:jsr EHexout:dey:lda (p),y:jsr EHexout
jsr ECrlfout
#endif
	lda p2
	ora p2+1
	bne fok
			; insert before the first free buffer so far
	ldy #0
	lda flist
	sta (p3),y
	iny
	lda flist+1
	sta (p3),y
	lda p3
	sta flist
	ldy p3+1
	sty flist+1
	jsr bmerge
#if 0	/*def DEBUGMEM*/
jsr printmem
#endif
	clc
	rts
fok			; insert to list
	ldy #1
	lda p+1		;lda (p2),y
	sta (p3),y
	dey
	lda p		;lda (p2),y
	sta (p3),y
	lda p3
	sta (p2),y
	iny
	lda p3+1
	sta (p2),y

	lda p3
	ldy p3+1
	jsr bmerge
	lda p2
	ldy p2+1
	jsr bmerge
#if 0	/*def DEBUGMEM*/
jsr printmem
#endif	
	clc
	rts
	.)

/**************************************************************************/
/* split buffer xr at size a/y for first part. return new buffer ID in x */
&bsplit	.(
	stx slot
#if 0 /*def DEBUGMEM*/
pha
tya
pha
DB("^m^jbsplit buffer ")
txa
jsr EHexout
pla
pha
jsr EHexout
pla
tay
pla
pha
jsr EHexout
jsr ECrlfout
pla
#endif
	sta p3
	sty p3+1
/*pha:tya:pha:DB("bsplit "):jsr printlist:jsr ECrlfout:pla:tay:pla*/

	clc
	adc #MINBUF-1
	and #MINMASK
	sta p2
	bcc l0
	iny
l0 	sty p2+1

	lda slotownr,x
	beq splitownr

	tya
	cmp slothlen,x
	bcc ok
	bne oops
	lda p2
	cmp slotllen,x
	bcc ok
	bne oops

/*DB("Btrunc to same size!^m^j")*/
	lda p3
	sta slotrlln,x
	lda p3+1
	sta slotrhln,x
	sec
	rts

oops	DB("bsplit: oops^m^j")
	sec
	rts

splitownr
	DB("bsplit: no owner!^m^j")
	jmp oops

ok	lda p3
	sta slotrlln,x
	lda p3+1
	sta slotrhln,x

/*DB("slot="):lda slot:jsr EHexout:jsr ECrlfout*/
	jsr getbslot
	bcs oops

	ldy slot
	clc
	lda slotladr,y
	adc p2
	sta slotladr,x
	lda slothadr,y
	adc p2+1
	sta slothadr,x
	sec
	lda slotllen,y
	sbc p2
	sta slotllen,x
	lda slothlen,y
	sbc p2+1
	sta slothlen,x
	
	lda p2
	sta slotllen,y
	lda p2+1
	sta slothlen,y

	inc slotownr,x	
oknull	
#if 0
DB("^m^jsplit buffer @")
	jsr printlist
#ifdef DEBUGMEM
	txa
	jsr EHexout
	lda slothadr,x
	jsr EHexout 
	lda slotladr,x
	jsr EHexout 
	lda slothlen,x
	jsr EHexout 
	lda slotllen,x
	jsr EHexout 
	jsr ECrlfout
jsr printmem
#endif
#endif
	clc
	rts
	.)

/**************************************************************************/
/* truncate buffer xr to size a/y */
&btrunc	.(
	jsr bsplit
	bcs oops
	jmp bfree2
oops	rts
	.)

/* realloc buffer xr to size a/y */
/* produce assemble errror
&brealloc .(
	.)
*/

/* get adress of buffer */
&getbadr .(
	cpx #MAXSLOT
	bcs maxerr
	lda slotownr,x
	beq err
	lda slotladr,x
	ldy slothadr,x
	clc
	rts
err	
#if 0
	DB("getbadr from unused slot=")
	txa
	jsr EHexout
	DB("!^m^j")
#endif
	sec
	rts
maxerr	DB("getbadr from illegal slot^m^j")
	sec
	rts
	.)

/* get length of buffer */
&getblen .(
	lda slotrlln,x
	ldy slotrhln,x
	clc
	rts
	.)

/* this registers one more user - so one bfree is ignored */
&incownr .(
	cpx #MAXSLOT
	bcs err
	lda slotownr,x
	beq incerr
	inc slotownr,x
	clc
	rts
err	DB("incownr: illegal buffer^m^j")
	sec
	rts
incerr	DB("incownr: unused buffer^m^j")
	sec
	rts
	.)

/* get free buffer-ID slot */
getbslot .(
	ldx #0
l0
	clc
	lda slotownr,x
	beq found
	inx
	cpx #MAXSLOT
	bcc l0
found
	rts
	.)

/* check if two free buffers (i.e. a/y plus following) can be merged */
bmerge	.(
	sta p
	sty p+1
	ldy #2
	clc
	lda (p),y
	adc p
	sta p3
	iny
	lda (p),y
	adc p+1
	sta p3+1
	ldy #0
	lda (p),y
	cmp p3
	bne nomerge
	iny
	lda (p),y
	cmp p3+1
	bne nomerge
merge
	ldy #2
	clc
	lda (p3),y
	adc (p),y
	sta (p),y
	iny
	lda (p3),y
	adc (p),y
	sta (p),y
	ldy #0
	lda (p3),y
	sta (p),y
	iny
	lda (p3),y
	sta (p),y
nomerge
	clc
	rts
	.)

/**************************************************************************/
#ifdef DEBUGMEM

	.data
pac	.byt 0
pxr	.byt 0
pyr	.byt 0
	.text

&printlist .(
	php
	sta pac
	stx pxr
	sty pyr

	ldx #0
l0	lda slotownr,x
	beq next
	txa
	jsr EHexout
	lda #":"
	jsr ECout
	lda slotownr,x
	jsr EHexout
	lda #"@"
	jsr ECout
	lda slothadr,x
	jsr EHexout
	lda slotladr,x
	jsr EHexout
	lda #"["
	jsr ECout
	lda slothlen,x
	jsr EHexout
	lda slotllen,x
	jsr EHexout
	DB("] ")

	lda slotladr,x
	and #%00000111
	bne error
next
	inx
	cpx #MAXSLOT
	bcc l0
	jsr ECrlfout

	lda pac
	ldx pxr
	ldy pyr
	plp
	rts
error	brk
	.)

&printmem .(
	php
	sta pac
	stx pxr
	sty pyr

DB("^m^jMemory Free List:^m^j")
	lda flist
	sta p
	lda flist+1
	sta p+1
	ldx #STDERR
loop
	lda p+1
;	beq ende
	jsr EHexout
	lda p
	jsr EHexout
	lda #"["
	jsr Fputc
	ldy #3
	lda (p),y
	jsr EHexout
	dey
	lda (p),y
	jsr EHexout
	DB("]->")
	ldy #1
	lda (p),y
	jsr EHexout
	dey
	lda (p),y
	jsr EHexout
	jsr ECrlfout

	ldy #1
	lda (p),y
	pha
	dey
	lda (p),y
	sta p
	pla
	sta p+1
	ora p
	bne loop

	lda pac
	ldx pxr
	ldy pyr
	plp
	rts
ende	brk
	.)
#endif

	.)