/**
 * @file tlb.c
 * @brief TLB handling
 * 
 */


#include "tlb.h"
#include "sys.h"
#include "debug.h"


/**
 * @brief Initializes TLB.
 *
 * Each of the TLB entries is cleared and invalidated, new entries will
 * be created on demand by the TLB Refill handler.
 */
void
init_tlb (void)
{
	unsigned int u;

	/* no wired pages */
	write_cp0_wired (0);

	/* init a null page */
	write_cp0_pagemask (PAGEMASK_4K);
	write_cp0_entrylo0 (0);
	write_cp0_entrylo1 (0);
	write_cp0_entryhi (cp0_entryhi_asid_mask);	/* unused asid */

	/* copy the null page to all TLB entries */
	for (u = 0; u < 48; u++) {
		write_cp0_index (u);
		TLBWI ();
	}
}


/**
 * @brief A TLB Refill exception handler.
 *
 * The handler creates a 1:1 mapping between physical and virtual memory and
 * is meant only as an example to demonstrate the work required to create
 * new virtual-to-physical memory mapping.
 */
void
tlbrefill (void)
{
	unsigned int badvaddr;
	unsigned int entrylo;

	/*
	 * Stop MSIM on tlbrefill, because it should not
	 * occur with kallisto.
	 */
	___stop ();

	/*
	 * First, get the faulting address.
	 */
	badvaddr = read_cp0_badvaddr ();

	/*
	 * Second, prepare a TLB entry describing two 4K pages for the
	 * even and odd addresses derived from badvaddr.
	 */
	write_cp0_pagemask (PAGEMASK_4K);
	entrylo = ((badvaddr >> 6) & cp0_entrylo_pfn_mask) |
		cp0_entrylo_d_mask | cp0_entrylo_v_mask;
	write_cp0_entrylo0 (entrylo & ~(1 << cp0_entrylo_pfn_shift));
	write_cp0_entrylo1 (entrylo | (1 << cp0_entrylo_pfn_shift));
	write_cp0_entryhi (badvaddr & cp0_entryhi_vpn2_mask);

	/*
	 * Third, write the entry to the TLB at random position.
	 */
	TLBWR ();
}
