************************************************************************** ** ** ** MEMORY - Die schnellste, beste, kürzeste Speicherverwaltung :-) ** ** ** ** by Christian A. Weber, Zurich/Switzwerland ** ** ** ************************************************************************** ** ** ** Modification History ** ** -------------------- ** ** ** ** 15-May-89 CHW Created this file! ** ** 27-Nov-89 CHW Fast-Memory added ** ** 30-Jul-90 CHW Chip allocation for AllocFastMem() works now ** ** 18-Sep-90 CHW Chip allocation for AllocFastMem() really works ** ** 20-Nov-90 CHH NoMemHandler eingebaut ** ** ** ************************************************************************** OPT OW6+ IDNT Memory SECTION text,CODE INCLUDE "MyExec.i" XREF MyNoMemHandler XDEF InitChipMemFunc,InitFastMemFunc XDEF AllocMemFunc,AllocClearMemFunc XDEF AllocFastMemFunc,AllocFastClearMemFunc XDEF FreeMemFunc,CopyMemQuickFunc,CopyMemFunc,ClearMemFunc XDEF AvailMemFunc,AvailFastMemFunc,CheckMemFunc *************************************************************************** *** ChipMemHeader init, A0=Adresse, D0=Size des freien Blocks InitChipMemFunc: movem.l d0/a0-a1,-(SP) lea meb_ChipMRHeader(a6),a1 bra.s DoInitMem *** FastMemHeader init, A0=Adresse, D0=Size des freien Blocks InitFastMemFunc: movem.l d0/a0-a1,-(SP) lea meb_FastMRHeader(a6),a1 ;; bra.s DoInitMem DoInitMem: move.l a0,mh_Lower(a1) move.l a0,mh_First(a1) move.l d0,mh_Free(a1) move.l d0,mc_Bytes(a0) clr.l mc_Next(a0) adda.l d0,a0 move.l a0,mh_Upper(a1) movem.l (SP)+,d0/a0-a1 rts *************************************************************************** *** D0: Amount, gibt D0: Adresse oder ruft AllocChipMem() auf AllocFastMemFunc: IFD DEBUG bsr CheckMemFunc ENDC movem.l d1-d3/a0-a3,-(SP) move.l d0,d1 ; Amount retten tst.l meb_FastMRHeader+mh_Free(a6) ; Fast RAM vorhanden ? beq.s ChipEntry ; nein ---> lea meb_FastMRHeader(a6),a0 ; The MemoryRegionHeader SMSG <"AllocFastMem(%ld), free=%ld">,d1,mh_Free(a0) bsr DoAlloc ; Speicher holen bne.s 1$ ; OK ---> move.l d1,d0 ; Amount bra.s ChipEntry ; ---> CHIP RAM holen 1$: movem.l (SP)+,d1-d3/a0-a3 rts *************************************************************************** *** D0: Amount, gibt D0: Adresse oder Guru *** Wenn nicht genuegen Speicher vorhanden ist, wird ein evt. *** vorhandener Handler angesprungen AllocMemFunc: IFD DEBUG bsr CheckMemFunc ENDC movem.l d1-d3/a0-a3,-(SP) move.l d0,d1 ; Amount retten ChipEntry: move.l d0,d3 lea meb_ChipMRHeader(a6),a0 ; The MemoryRegionHeader SMSG <"AllocChipMem(%ld), free=%ld">,d1,mh_Free(a0) bsr DoAlloc movem.l (SP)+,d1-d3/a0-a3 ;; tst.l d0 beq.s .NotEnough ; nicht genug ---> rts .NotEnough: movem.l d1-d7/a0-a6,-(SP) move.l d3,d1 ; Amount bsr MyNoMemHandler tst.w d0 beq .MemAlert movem.l (SP)+,d1-d7/a0-a6 move.l d3,d0 bra AllocMemFunc .MemAlert: movem.l (SP)+,d1-d7/a0-a6 lea meb_ChipMRHeader(a6),a0 ; MemoryRegionHeader für SMSG movea.l (SP)+,a1 ; PC für SMSG SMSG <"AllocMem: Can't allocate %ld bytes, free=%ld, MRH=$%08lx, PC=$%08lx">,d1,mh_Free(a0),a0,a1 jmp meb_ColdReboot(a6) *************************************************************************** *** D0: Amount, A0: MRH gibt D0: Adresse oder 0, rettet keine Regs! DoAlloc: tst.l d0 ; 0 Bytes reservieren ? beq .AllocError ; ja ---> Guru addq.l #4,d0 ; Remember-Size addq.l #7,d0 andi.b #$f8,d0 ; Bytezahl modulo 8 aufrunden jsr meb_Disable(a6) lea mh_First(a0),a2 ; Zeiger auf 1. freien Chunk .AllocLoop: move.l (a2),d2 ; Link zum nächsten Chunk beq.s .NotEnoughMemory ; Liste zu Ende ---> Guru movea.l d2,a1 ; Nächster Blockanfang cmp.l mc_Bytes(a1),d0 ; Chunklänge > Amount ? bls.s 1$ ; ja ---> Chunk gefunden! movea.l a1,a2 ; Nächster Blockanfang bra.s .AllocLoop ; ---> Loop 1$: beq.s 2$ ; Chunklänge == Amount ---> lea 0(a1,d0.l),a3 ; Anfang des Restchunks move.l (a1),(a3) ; Link eintragen move.l mc_Bytes(a1),d2 ; Länge des freien Blocks sub.l d0,d2 ; minus amount move.l d2,mc_Bytes(a3) ; gibt Länge des Restchunks move.l a3,(a2) ; Vorherigen Link korrigieren bra.s 3$ ; ---> 2$: move.l (a1),(a2) ; Link zurückkopieren 3$: sub.l d0,mh_Free(a0) ; Frei-Zähler anpassen move.l d0,(a1)+ ; Grösse für FreeMem eintragen move.l a1,d0 ; Allozierter Bereich .AllocEnd: jsr meb_Enable(a6) ; versabbert CCR! tst.l d0 rts .NotEnoughMemory: moveq.l #0,d0 bra.s .AllocEnd .AllocError: IFD DEBUG addq.w #4,SP ; back to Alloc(Fast)?MemFunc movem.l (SP)+,d1-d2/a0-a3 ; discard saved regs movea.l (SP)+,a5 ; PC of caller SMSG <"AllocMem: Got request for 0 bytes, PC=$%08lx">,a5 ENDC jmp meb_ColdReboot(a6) ************************************************************************** *** FAST-Speicher reservieren und löschen AllocFastClearMemFunc: movem.l d1/a0,-(SP) move.l d0,d1 ; Amount retten bsr AllocFastMemFunc bra.s DoAllocClear ; ---> ************************************************************************** *** CHIP-Speicher reservieren und löschen AllocClearMemFunc: movem.l d1/a0,-(SP) move.l d0,d1 ; Amount retten bsr AllocMemFunc DoAllocClear: movea.l d0,a0 ; Adresse move.l d1,d0 ; Länge bsr ClearMemFunc move.l a0,d0 ; Adresse movem.l (SP)+,d1/a0 rts *************************************************************************** *** Speicherbereich (A1) freigeben FreeMemFunc: movem.l d0-d2/a0-a2,-(SP) jsr meb_Disable(a6) move.l a1,d0 ; Null ? beq .FreeEnd ; ja ---> cmp.l meb_ChipMRHeader+mh_Upper(a6),d0 ; Ist's CHIP-RAM ? bhs.s 1$ ; nein ---> lea meb_ChipMRHeader(a6),a0 ; The MemoryRegionHeader bra.s 2$ 1$: lea meb_FastMRHeader(a6),a0 2$: move.l -(a1),d0 ; Länge des Blocks beq .FreeError ; ja ---> Guru move.l a1,d1 ; Freizugebender Block lea mh_First(a0),a2 ; Zeiger auf 1. freien Chunk move.l (a2),d2 ; Link zum nächsten Chunk beq.s 5$ ; Ende der Liste ---> 3$: cmpa.l d2,a1 ; Start des freizugebenden Chunks bcs.s 4$ ; < Anfang des Blocks ---> beq .FreeError ; == Anfang ---> Guru movea.l d2,a2 ; Link zum nächsten Chunk move.l (a2),d2 ; Neuer Link bne.s 3$ ; Liste geht weiter ---> Loop 4$: moveq #mh_First,d1 ; war 16 (?) add.l a0,d1 ; + MemoryRegionHeader cmp.l a2,d1 ; zeigt A2 auf mh_First ? beq.s 5$ ; ja ---> Spezialfall move.l mc_Bytes(a2),d2 ; Länge des freien Chunks add.l a2,d2 ; + Anfang = Chunk-Ende cmp.l a1,d2 ; Anfang des freizugebenden Chunks beq.s 6$ ; == Ende des freien Chunks ---> bhi.s .FreeError ; im freien Bereich ---> Guru 5$: move.l (a2),(a1) ; Neuen Blockheader erzeugen move.l a1,(a2) move.l d0,mc_Bytes(a1) bra.s 7$ ; ---> 6$: add.l d0,mc_Bytes(a2) ; Blocklänge += Freibytes move.l a2,a1 ; Blockanfang 7$: tst.l (a1) ; Link eingetragen ? beq.s 8$ ; nein ---> move.l mc_Bytes(a1),d2 ; Blocklänge add.l a1,d2 ; + Anfang = Ende+1 cmp.l (a1),d2 ; mit Linkadresse vergleichen bhi.s .FreeError ; Linkadr. kleiner ---> Guru bne.s 8$ ; Linkadresse grösser ---> move.l (a1),a2 ; Nächsten Chunk einlinken move.l (a2),(a1) move.l mc_Bytes(a2),d2 add.l d2,mc_Bytes(a1) 8$: add.l d0,mh_Free(a0) ; Frei-Zähler anpassen .FreeEnd: jsr meb_Enable(a6) movem.l (SP)+,d0-d2/a0-a2 rts .FreeError: movem.l (SP)+,d0-d2/a0-a2 movea.l (SP)+,a5 SMSG <"FreeMem: MemList corrupt, MRH=$%08lx, PC=$%08lx">,a0,a5 jmp meb_ColdReboot(a6) *************************************************************************** CheckMemFunc: movem.l d0-d1/a0-a1,-(SP) jsr meb_Disable(a6) lea meb_ChipMRHeader(a6),a0 bsr.s CheckMemList ; CHIP RAM testen tst.l meb_FastMRHeader+mh_First(a6) ; FAST RAM vorhanden ? beq.s 1$ lea meb_FastMRHeader(a6),a0 bsr.s CheckMemList ; FAST RAM testen 1$: jsr meb_Enable(a6) movem.l (SP)+,d0-d1/a0-a1 rts *** Speicherliste (A0) testen, Message falls korrupt CheckMemList: IFD VERBOSE SMSG <"CheckMemList: mh_Lower=$%08lx, mh_Upper=$%08lx, mh_Free=%ld">,mh_Lower(a0),mh_Upper(a0),mh_Free(a0) ENDC moveq.l #0,d1 ; Free-Count löschen movea.l mh_First(a0),a1 ; 1. freier Chunk .CheckLoop: IFD VERBOSE SMSG <" Chunk $%08lx: %ld bytes, mc_Next=$%08lx">,a1,mc_Bytes(a1),mc_Next(a1) ENDC add.l mc_Bytes(a1),d1 ; FreeCount += bytes move.l mc_Next(a1),d0 ; Link zum nächsten Chunk beq.s 1$ ; Ende der Liste ---> cmp.l a1,d0 ; Next < actual ? bls.s .CheckError ; ja ---> Error movea.l d0,a1 bra.s .CheckLoop 1$: cmp.l mh_Free(a0),d1 ; FreeCount richtig ? bne.s .CheckError IFD VERBOSE SMSG <" Memory List OK!"> ENDC rts .CheckError: SMSG <"CheckMem: List corrupt, soll=%ld, ist=%ld, MRH=$%08lx">,mh_Free(a0),d1,a0 jmp meb_ColdReboot(a6) ************************************************************************** *** Speicher schnell kopieren, WORD-aligned, Länge % 4 = 0 CopyMemQuickFunc: movem.l d0-d1/a0-a1,-(SP) moveq #0,d1 ; Kein Byte-Rest bra.s l272 ; ---> *** Speicher normal kopieren CopyMemFunc: movem.l d0-d1/a0-a1,-(SP) moveq #12,d1 cmp.l d1,d0 ; Länge < 12 ? bcs.s l277 ; ja ---> byteweise kopieren move.l a0,d1 ; Source btst #0,d1 ; Gerade ? beq.s l271 ; ja ---> move.b (a0)+,(a1)+ ; Sonst 1 Byte kopieren subq.l #1,d0 l271: move.l a1,d1 ; Destination btst #0,d1 ; Gerade ? bne.s l277 ; nein ---> byteweise kopieren move.l d0,d1 ; Länge andi.w #3,d1 ; Byte-Rest von LONGs l272: move.w d1,-(SP) ; Rest retten für später moveq #96,d1 ; 2* Länge von 12 Registern cmp.l d1,d0 bcs.s l274 ; movem lohnt sich nicht ---> movem.l d1-d7/a2-a6,-(SP) ; Alles retten l273: movem.l (a0)+,d1-d7/a2-a6 movem.l d1-d7/a2-a6,(a1) moveq #48,d1 ; 12 LONG-Register adda.l d1,a1 ; INC dest sub.l d1,d0 ; DEC len cmp.l d1,d0 ; nochmal ? bcc.s l273 ; ja ---> movem.l (SP)+,d1-d7/a2-a6 l274: lsr.l #2,d0 ; restliche Longwords beq.s l276 ; keine ---> subq.l #1,d0 ; für dbf move.l d0,d1 swap d0 l275: move.l (a0)+,(a1)+ dbf d1,l275 dbf d0,l275 l276: move.w (SP)+,d1 ; Geretteter Byte-Rest beq.s l27a ; 0 ---> moveq #0,d0 bra.s l279 ; byteweise kopieren l277: move.w d0,d1 swap d0 bra.s l279 l278: move.b (a0)+,(a1)+ l279: dbf d1,l278 dbf d0,l278 l27a: movem.l (SP)+,d0-d1/a0-a1 rts ************************************************************************** *** Speicher löschen, A0 : Adresse, D0 : Länge in Bytes ( <=1MB! ) ClearMemFunc: movem.l d0-d2/a0,-(SP) SMSG <"ClearMem: %ld bytes at $%08lx">,d0,a0 moveq.l #0,d2 ; Lösch-Register move.l a0,d1 btst #0,d1 ; Adresse gerade ? beq.s 1$ ; ja ---> subq.l #1,d0 ; DEC len bmi.s 99$ ; Länge war 0 ---> move.b d2,(a0)+ ; 1 Byte löschen 1$: move.l d0,d1 ; Länge lsr.l #4,d1 ; /16 weil 4 LONGs aufs mal bra.s 3$ ; Für dbf 2$: move.l d2,(a0)+ move.l d2,(a0)+ move.l d2,(a0)+ move.l d2,(a0)+ 3$: dbf d1,2$ andi.w #15,d0 ; restliche Bytes bra.s 5$ ; Für dbf 4$: move.b d2,(a0)+ 5$: dbf d0,4$ 99$: movem.l (SP)+,d0-d2/a0 rts *************************************************************************** *** Anzahl freie Bytes CHIP-RAM nach D0 AvailMemFunc: move.l meb_ChipMRHeader+mh_Free(a6),d0 rts *************************************************************************** *** Anzahl freie Bytes FAST-RAM nach D0 AvailFastMemFunc: move.l meb_FastMRHeader+mh_Free(a6),d0 rts END