#include "vmem.h" /******************************************/ /* Adressierung des virtuellen Speichers: */ /******************************************/ char *vm_address (address, window_size, mode) V_ADR address; long *window_size; int mode; { VPAGE vmempage, lastpage; CPAGE select; WORD start_offset, count, i; vmempage = GET_PAGE (address); start_offset = GET_OFFSET (address); #ifdef DEBUG printf ("\nVM_ADDRESS: page: %x offset: %x", vmempage, start_offset); #endif if ((vmempage >= info.count_page) || (flags [vmempage] == FREE)) return ((char *) ILLEGAL_ADDRESS); if (*window_size <= 0) return ((char *) ILLEGAL_COUNT); if ((mode != READ_MODE) && (mode != WRITE_MODE)) return ((char *) ILLEGAL_MODE); *window_size = MIN (*window_size, info.cache_size - start_offset); count = GET_COUNT (*window_size + start_offset); lastpage = vmempage + count - 1; /* Sequenz im Cache suchen: Algorithmus 1 */ if ((select = search_sequence (vmempage, lastpage)) == EMPTY_ENTRY) { ULONG age, best_age; /* keine geeignete Sequenz im Cache gefunden: Algorithmus 2 starten */ select = 0; age = 0; /* Gesamt-Alter der 1. Cache-Sequenz bestimmen: */ for (i = 0; i < count; i++) age += (ULONG) cache_age [i]; best_age = age; /* "jngere" Cache-Sequenz suchen: */ for ( ; i < info.cache_count; i++) { age = age - (ULONG) cache_age [i-count] + (ULONG) cache_age [i]; if (age < best_age) { best_age = age; select = i - count + 1; } } } #ifdef DEBUG printf ("\nVM_ADDRESS: %x PAGES FROM CACHE %x", count, select); #endif /* Belegte unbrauchbare Seiten innerhalb der Cache-Sequenz auslagern: */ for (i = select; i < (select + count); i++) { if (cache_flags [i] != CACHE_FREE) { VPAGE vpage = cache_page [i]; if (OUTSIDE (vpage, vmempage, lastpage)) { #ifdef DEBUG printf ("\nVM_ADDRESS: REMOVE CACHE %x (PAGE: %x, Flag: %x)", i, cache_page [i], cache_flags [i]); #endif if (cache_flags [i] == CACHE_WRITE) write_page (CACHE_ADDRESS (i), vpage); else CACHE_TO_FILE (vpage); FREE_CACHE (i); } } } /* Durchsuchen des Caches nach Seiten, die zur Sequenz geh”ren: */ for (i = 0; i < info.cache_count; i++) { if (cache_flags [i] != CACHE_FREE) { VPAGE vpage = cache_page [i]; if (INSIDE (vpage, vmempage, lastpage)) { WORD source, dest; dest = vpage - vmempage + select; source = search_cache (vpage); if (source != dest) { if (cache_flags [dest] == CACHE_FREE) { COPY_CACHE (CACHE_ADDRESS (dest), CACHE_ADDRESS (source)); ALLOC_CACHE (dest, cache_flags [source], vpage); FREE_CACHE (source); } else /* CACHE is used */ { WORD other = cache_page [dest] - vmempage + select; if (cache_flags [other] == CACHE_FREE) { COPY_CACHE (CACHE_ADDRESS (other), CACHE_ADDRESS (dest)); ALLOC_CACHE (other, cache_flags [dest], cache_page [dest]); COPY_CACHE (CACHE_ADDRESS (dest), CACHE_ADDRESS (source)); ALLOC_CACHE (dest, cache_flags [source], vpage); FREE_CACHE (source); } else /* CACHE is used */ { if (cache_flags [dest] == CACHE_WRITE) write_page (CACHE_ADDRESS (dest), cache_page [dest]); else CACHE_TO_FILE (cache_page [dest]); COPY_CACHE (CACHE_ADDRESS (dest), CACHE_ADDRESS (source)); ALLOC_CACHE (dest, cache_flags [source], vpage); FREE_CACHE (source); } } } } } } /* restliche Seiten in den Cache einlagern: */ for (i = select; i < (select + count); i++) { if (cache_flags [i] == CACHE_FREE) { VPAGE vpage = vmempage + i - select; read_page (CACHE_ADDRESS (i), vpage); FILE_TO_CACHE (vpage); ALLOC_CACHE (i, mode, vpage); } else { UPDATE_FLAG (i, mode); #ifdef DEBUG2 printf ("\nUPDATE 2: CACHE %x WITH %x", i, mode); #endif } ACCESSED (i); } return ((char *) (CACHE_ADDRESS (select) + start_offset)); } /* alle Sequenzen im Cache untersuchen: */ WORD search_sequence (vmempage, lastpage) VPAGE vmempage, lastpage; { SEQ *sequences, *seq2; WORD scount, soldpage, border, i; sequences = (SEQ *) buffer; sequences->count = 0; scount = 0; soldpage = EMPTY_ENTRY; border = (lastpage - vmempage + 2) >> 1; /* alle gltigen Sequenzen erstellen: */ for (i = 0; i < info.cache_count; i++) { if (cache_flags [i] == CACHE_FREE) { if (scount >= border) { sequences->count = scount; sequences++; sequences->count = 0; } scount = 0; soldpage = EMPTY_ENTRY; } else /* CACHE is used */ { if (OUTSIDE (cache_page [i], vmempage, lastpage)) { if (scount >= border) { sequences->count = scount; sequences++; sequences->count = 0; } scount = 0; soldpage = EMPTY_ENTRY; } else /* INSIDE */ { if (cache_page [i] != (soldpage + scount)) { if (scount >= border) { sequences->count = scount; sequences++; sequences->count = 0; } scount = 1; sequences->cachepage = i; sequences->vmempage = soldpage = cache_page [i]; } else /* Sequence continues */ { scount++; } } } } /* Sequenz suchen, die alle gewnschten Seiten beinhaltet: */ sequences = (SEQ *) buffer; while (sequences->count != 0) { if ((sequences->vmempage <= vmempage) && ((sequences->vmempage + sequences->count) > lastpage)) { return (sequences->cachepage - (sequences->vmempage - vmempage)); } sequences++; /* Zeiger auf n„chste gefundene Sequenz */ } /* Sequenz suchen, bei der am Anfang und am Ende angefgt werden kann: */ for (;;) { seq2 = sequences = (SEQ *) buffer; scount = 0; while (seq2->count != 0) { if (seq2->count > scount) { scount = seq2->count; sequences = seq2; } seq2++; } /* War die Suche vergeblich ? */ if (scount <= 1) return (EMPTY_ENTRY); /* K”nnen Seiten am Anfang eingelagert werden ? */ if (sequences->vmempage > vmempage) { if ((sequences->vmempage - vmempage) <= sequences->cachepage) scount = 1; else scount = 0; } else scount = 1; /* K”nnen Seiten am Ende eingelagert werden ? */ if ((sequences->vmempage + sequences->count - 1) < lastpage) { if ((info.cache_count - sequences->cachepage) >= (lastpage + 1 - sequences->vmempage)) { scount += 2; } } else scount += 2; /* Platz am Anfang und am Ende ? */ if (scount == 3) return (sequences->cachepage - (sequences->vmempage - vmempage)); /* Feld l”schen; Suche fortsetzen: */ sequences->count = 1; } }