#include "vmem.h"

/**********************/
/* Globale Variablen: */
/**********************/

V_INFO		info;		/* Informationsblock */

WORD	max_page;		/* bisher gr”žte Datei-Seiten-Nummer */

BYTE	*flags;			/* Flags fr den virtuellen Speicher */

CPAGE	*cache_page;	/* Umsetztabelle Cache-Seite => Speicher-Seite */
BYTE	*cache_flags;	/* Flags fr den Cache */
ULONG	*cache_age;		/* LRU-Age fr den Cache */
WORD	age_count;		/* Anzahl der Age-LONGS */
ULONG	lru_count;		/* Timer fr LRU-Aging */

BYTE	*cache;			/* eigentlicher Seiten-Cache */
BYTE	*buffer;		/* Puffer fr eine Seite */

int		sector_flag;	/* Flag fr die Verwendung von BIOS-Routinen */
WORD	*sector_no;		/* Sektor-Nummern der jeweiligen Seiten */

BPB		*bpb_block;		/* Zeiger auf aktuellen BPB-Block */
WORD	size_bits;
WORD	record_bits;
WORD	cluster_bits;
WORD	cluster_size;
WORD	sector_mask;
WORD	sectors;
WORD	drive;

WORD	offset_bits;	/* Anzahl der Bits, die den Offset bestimmen */
WORD	offset_mask;	/* Maske fr die Offset-Bits */

MD		used_list;		/* Belegtliste */
MD		free_list;		/* Freiliste */

MEMORY	md_array [MAX_BLOCKS];	/* Speicher fr Memory Deskriptoren */

int		tmp_handle;				/* Handle fr die tempor„re Datei */
char	tmp_file [] = TMP_FILE;	/* Name und Pfad der tempor„ren Datei */

/********************************************************/
/* Konfiguration des Caches sowie der n”tigen Tabellen: */
/********************************************************/

int vm_config (parameter)
	TAB	*parameter;
{
	DISKINFO	dbuffer;
	int			i;
	long		drivemap;

	if (info.version != 0)				/* schon mal konfiguriert ? */
		vm_close ();

	if (parameter->cache_size < 4)		/* mindestens 4 Seiten */
		return (WRONG_CACHE_SIZE);

	if (parameter->page_type > SIZE_32768)
		return (WRONG_PAGE_TYPE);

	drivemap = Drvmap ();
	info.drive_no = parameter->drive_no;
	drive = parameter->drive_no - 1;

	if ((drive < 2)
	|| ((drivemap & (1 << drive)) == 0))
		return (ILLEGAL_DRIVE);

	bpb_block = Getbpb (drive);
	if (bpb_block->bflags != 1)
		return (ILLEGAL_FATSIZE);

	record_bits = 0;
	i = bpb_block->recsiz;
	while (i >>= 1)
		++record_bits;

	cluster_bits = 0;
	i = bpb_block->clsiz;
	while (i >>= 1)
		++cluster_bits;

	sector_mask = (1 << (record_bits - cluster_bits)) - 1;
	sectors = 1 + bpb_block->fsiz * 2 + bpb_block->rdlen
			+ (bpb_block->numcl * bpb_block->clsiz);

	Dfree (&dbuffer, info.drive_no);
	info.drive_free = dbuffer.b_free << 10;

	offset_bits = 10 + parameter->page_type;
	offset_mask = (1 << offset_bits) - 1;

	lru_count = 0;

	age_count = parameter->cache_size;

	info.version = VERSION;
	info.count_page = parameter->count_page;
	info.count_blocks = info.free_blocks = MAX_BLOCKS;
	info.fill_value = parameter->fill_value;
	info.page_size = PAGE_TO_ADDR (1);
	info.cache_size = PAGE_TO_ADDR (parameter->cache_size);
	info.cache_count = parameter->cache_size;
	info.max_size = PAGE_TO_ADDR (info.count_page);
	info.max_alloc = PAGE_TO_ADDR (info.count_page);

	cluster_size = bpb_block->clsiz;
	if (info.page_size == bpb_block->clsizb)
	{
		size_bits = 0;
		sector_flag = 1;
	}
	else if (info.page_size == (bpb_block->clsizb + bpb_block->clsizb))
	{
		cluster_size += cluster_size;
		size_bits = 1;
		sector_flag = 1;
	}
	else if (info.page_size == (bpb_block->clsizb << 2))
	{
		cluster_size <<= 2;
		size_bits = 2;
		sector_flag = 1;
	}
/*	else*/
	{
		tmp_file [0] = 'C' - 3 + info.drive_no;
		Fdelete (tmp_file);
		if ((tmp_handle = Fcreate (tmp_file, 0)) < 0)
			return (tmp_handle);
		sector_flag = 0;
	}

/* Speicheranforderung der ben”tigten Arrays: */

	MALLOC (flags, BYTE, info.count_page+1);
	if (sector_flag)
	{
		MALLOC (sector_no, SECTOR, info.count_page+1);
	}
	else
		sector_no = NULL;
	MALLOC (cache_page, VPAGE, info.cache_count);
	MALLOC (cache_flags, BYTE, info.cache_count);
	MALLOC (cache_age, ULONG, info.cache_count);
	MALLOC (cache, BYTE, info.cache_size);
	MALLOC (buffer, BYTE, info.page_size);

/* Initialisierung der ben”tigten Arrays: */

	max_page = 1;

	if (!sector_flag)
	{
		if ((i = init_pages (1, 1)) != OK)
			return (i);

		Fclose (tmp_handle);

		if ((tmp_handle = Fopen (tmp_file, 2)) < 0)
			return (tmp_handle);
	}

	for (i = 0; i < info.count_page; i++)		/* Datei-Parameter */
		flags [i] = FREE;

	if (sector_flag)
		for (i = 0; i < info.count_page; i++)	/* Sektor-Daten */
			sector_no [i] = EMPTY_ENTRY;

	for (i = 0; i < info.cache_count; i++)		/* Cache-Parameter */
		FREE_CACHE (i);

	for (i = 0; i < (age_count + 4); i++)
		cache_age [i] = 0;

	used_list = NIL;
	free_list = 0;
	INSERT_MD (0, 1, info.count_page, NIL);

	for (i = 1; i < MAX_BLOCKS; i++)
		DELETE_MD (i);

	return (OK);
}


/***********************************/
/* Schliežen der tempor„ren Datei: */
/***********************************/

void vm_close ()
{
	if (!sector_flag)
	{
		Fclose (tmp_handle);	/* Datei schliežen, */
		Fdelete (tmp_file);
	}

	Mfree (buffer);
	Mfree (cache);
	Mfree (cache_age);
	Mfree (cache_flags);
	Mfree (cache_page);
	if (sector_flag)
		Mfree (sector_no);
	Mfree (flags);
}

/*********************************/
/* šbergabe der V_INFO-Struktur: */
/*********************************/

V_INFO *vm_info (void)
{
	return (&info);
}

/********************************************/
/* Neu-Initialisierung des gesamten Caches: */
/********************************************/

void vm_clrcache (void)
{
	cache_clr (0, info.cache_count);
}
