#include "armdefs.h"

/*chy 2004-06-06, fix bug found by wenye@cs.ucsb.edu*/
ARMword rb_masks[] = {
	0x0,			//RB_INVALID
	4,			//RB_1
	16,			//RB_4
	32,			//RB_8
};

/*mmu_rb_init
 * @rb_t	:rb_t to init
 * @num		:number of entry
 * */
int
mmu_rb_init (rb_t * rb_t, int num)
{
	int i;
	rb_entry_t *entrys;

	entrys = (rb_entry_t *) malloc (sizeof (*entrys) * num);
	if (entrys == NULL) {
		printf ("SKYEYE:mmu_rb_init malloc error\n");
		return -1;
	}
	for (i = 0; i < num; i++) {
		entrys[i].type = RB_INVALID;
		entrys[i].fault = 0;
	}

	rb_t->entrys = entrys;
	rb_t->num = num;
	return 0;
}

/*mmu_rb_exit*/
void
mmu_rb_exit (rb_t * rb_t)
{
	free (rb_t->entrys);
};

/*mmu_rb_search
 * @rb_t	:rb_t to serach
 * @va		:va address to math
 *
 * $	NULL :not match
 * 		NO-NULL:
 * */
rb_entry_t *
mmu_rb_search (rb_t * rb_t, ARMword va)
{
	int i;
	rb_entry_t *rb = rb_t->entrys;

	d_msg ("va = %x\n", va);
	for (i = 0; i < rb_t->num; i++, rb++) {
		//2004-06-06 lyh  bug from wenye@cs.ucsb.edu
		if (rb->type) {
			if ((va >= rb->va)
			    && (va < (rb->va + rb_masks[rb->type])))
				return rb;
		}
	}
	return NULL;
};

void
mmu_rb_invalidate_entry (rb_t * rb_t, int i)
{
	rb_t->entrys[i].type = RB_INVALID;
}

void
mmu_rb_invalidate_all (rb_t * rb_t)
{
	int i;

	for (i = 0; i < rb_t->num; i++)
		mmu_rb_invalidate_entry (rb_t, i);
};

void
mmu_rb_load (ARMul_State * state, rb_t * rb_t, int i_rb, int type, ARMword va)
{
	rb_entry_t *rb;
	int i;
	ARMword max_start, min_end;
	fault_t fault;
	tlb_entry_t *tlb;

	/*align va according to type */
	va &= ~(rb_masks[type] - 1);
	/*invalidate all RB match [va, va + rb_masks[type]] */
	for (rb = rb_t->entrys, i = 0; i < rb_t->num; i++, rb++) {
		if (rb->type) {
			max_start = max (va, rb->va);
			min_end =
				min (va + rb_masks[type],
				     rb->va + rb_masks[rb->type]);
			if (max_start < min_end)
				rb->type = RB_INVALID;
		}
	}
	/*load word */
	rb = &rb_t->entrys[i_rb];
	rb->type = type;
	fault = translate (state, va, D_TLB (), &tlb);
	if (fault) {
		rb->fault = fault;
		return;
	}
	fault = check_access (state, va, tlb, 1);
	if (fault) {
		rb->fault = fault;
		return;
	}

	rb->fault = 0;
	va = tlb_va_to_pa (tlb, va);
	//2004-06-06 lyh  bug from wenye@cs.ucsb.edu
	for (i = 0; i < (rb_masks[type] / 4); i++, va += WORD_SIZE) {
		rb->data[i] = mem_read_word (state, va);
	};
}
