/**
 * CacheSim.c
 * This program is designed for class exercise only.
 * It is provided as is. There is no warranty or support of any kind.
 *
 * Krerk Piromsopa, Ph.D.
 * Department of Computer Engineering
 * Chulalongkorn University
 * Bangkok, Thailand.
 *
 * History
 * 2013 - Initial design
 * 2015 - Refactor/Clean code
 * 2026 - Updated for Computer Architecture 2026 edition
**/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "CacheSim.h"

long MISS;
long HIT;
struct Cache cache[INDEX_SIZE];

int init() {
	MISS = 0;
	HIT  = 0;
	int i;
	for (i = 0; i < INDEX_SIZE; i++) {
		cache[i].valid = 0;
		cache[i].tag   = 0;
		cache[i].dirty = 0;
	}
	return 0;
}

int calAddr(unsigned long addr, unsigned long *tag,
            unsigned long *idx, unsigned long *offset) {
	unsigned long tmp;
	int i;
	*tag = addr >> (OFFSETLEN + INDEXLEN);
	tmp = 0;
	for (i = 0; i < INDEXLEN; i++) {
		tmp <<= 1;
		tmp  |= 0x01;
	}
	*idx = addr >> OFFSETLEN & tmp;
	tmp = 0;
	for (i = 0; i < OFFSETLEN; i++) {
		tmp <<= 1;
		tmp  |= 0x01;
	}
	*offset = addr & tmp;
	return 0;
}

int access(unsigned long addr) {
	unsigned long offset;
	unsigned long tag;
	unsigned long idx;
	calAddr(addr, &tag, &idx, &offset);
	if (cache[idx].tag == tag && cache[idx].valid) {
		HIT++;
	} else {
		MISS++;
		cache[idx].valid = 1;
		cache[idx].tag   = tag;
	}
	return 0;
}

int main(int argc, char *argv[]) {
	printf("CacheSim v.2026\n");
	printf("This program is designed for class exercise only.\n");
	printf("By Krerk Piromsopa, Ph.D.\n");
	FILE *input;
	char buff[1025];
	unsigned long myaddr;
	if (argc < 2) {
		fprintf(stderr, "Usage:\n\t%s address_file\n", argv[0]);
		exit(-1);
	}
	input = fopen(argv[1], "r");
	if (!input) {
		fprintf(stderr, "Cannot open file: %s\n", argv[1]);
		exit(-1);
	}
	/* read file — one hex address per line, e.g. 0x0804a3f0 */
	while (fgets(&buff[0], 1024, input)) {
		sscanf(buff, "0x%lx", &myaddr);
		access(myaddr);
	}
	fclose(input);
	printf("HIT: %7ld  MISS: %7ld  Total: %7ld  Miss rate: %.2f%%\n",
	       HIT, MISS, HIT + MISS,
	       100.0 * MISS / (HIT + MISS));
	return 0;
}
