/*
 * Copyright (C) 2014-2016 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#include <assert.h>
#include <inttypes.h>
#include <stdio.h>

static void
printb(int count, int v)
{
	int i;

	printf("0b");
	for (i = count - 1; 0 <= i; i--) {
		printf("%d", (v >> i) & 1);
	}
}

static void
_lru_set(uint8_t *info, int off, int bit)
{
	info[off / 8] &= ~(1 << (off % 8));
	info[off / 8] |= bit << (off % 8);
}

static int
_lru_get(uint8_t *info, int off)
{
	return (info[off / 8] >> (off % 8)) & 1;
}

static void
_lru_use(int count, uint8_t *info, int off, int used)
{
	if (1 < count) {
		int bit;

		bit = used & 1;
		used >>= 1;
		count >>= 1;
		_lru_set(info, off + used, bit);
		_lru_use(count, info, off + count, used);
	}
}

static void
lru_use(int count, uint8_t *info, int used)
{
	_lru_use(count, info, 0, used);
}


static int
_lru_oldest(int count, uint8_t *info, int off)
{
	int oldest;

	if (1 < count) {
		count >>= 1;
		oldest = _lru_oldest(count, info, off + count);
		oldest = (oldest << 1) + ! _lru_get(info, off + oldest);
	} else {
		oldest = 0;
	}

	return oldest;
}

static int
lru_oldest(int count, uint8_t *info)
{
	int oldest;

	oldest = _lru_oldest(count, info, 0);

	return oldest;
}

static void
table(int assoc)
{
	int i;

	/* use */
	printf("static const uint8_t NAME_(lru%d_use_table)[%d][%d] = {\n",
			assoc, 1 << (assoc - 1), assoc);
	for (i = 0; i < 1 << (assoc - 1); i++) {
		int u;

		printf("/*");
		printb(assoc - 1, i);
		printf("*/ {", i);
		for (u = 0; u < assoc; u++) {
			uint8_t info;

			info = i;
			lru_use(assoc, &info, u);
			printf(" ");
			printb(assoc - 1, info);
			printf(",");
		}
		printf(" },\n");
	}
	printf("};\n");

	/* old */
	printf("static const uint8_t NAME_(lru%d_old_table)[%d] = {\n",
			assoc, 1 << (assoc - 1));
	for (i = 0; i < 1 << (assoc - 1); i++) {
		uint8_t info;
		uint8_t oldest;

		printf("/*");
		printb(assoc - 1, i);
		printf("*/ ", i);
		info = i;
		oldest = lru_oldest(assoc, &info);
		printb(assoc, oldest);
		printf(",\n");
	}
	printf("};\n");
}

int
main(void)
{
	int assoc;

	for (assoc = 4; assoc <= 8; assoc *= 2) {
		table(assoc);
	}

	return 0;
}
