/******************************************************************************
** FILE: branch.c
** Branch predictor.
*/

#include <assert.h>
#include <sys/types.h>

#include "internal.h"
#include "param.h"

/* These are the functions that are called from Facile */

extern void xbranch_init();
extern uchar_t xbranch_predict(ulong_t);
extern void xbranch_direction(ulong_t,uchar_t);

/* Branch Predictor Statistics */

u_longlong_t count_branch_predict = 0;
u_longlong_t count_branch_direction = 0;

/*****************************************************************************/

#define BYTES_PER_INST 4
#define BRANCH_PREDICTOR_ENTRIES \
(BRANCH_PREDICTOR_SIZE*8/BRANCH_PREDICTOR_BITS)

#define SIGN_MASK (1 << (BRANCH_PREDICTOR_BITS-1))
#define MIN_VALUE (-1 << (BRANCH_PREDICTOR_BITS-1))
#define MAX_VALUE (~MIN_VALUE)

static signed char predictor[BRANCH_PREDICTOR_ENTRIES];

void
xbranch_init()
{
    ulong_t ii;
    for(ii=0; ii<BRANCH_PREDICTOR_ENTRIES; ++ii)
	predictor[ii] = 0;
}

uchar_t
xbranch_predict(ulong_t pc)
{
    ulong_t index;
#ifdef STATS
    ++count_branch_predict;
#endif
    index = (pc/BYTES_PER_INST) % BRANCH_PREDICTOR_ENTRIES;
    return !(predictor[index] & SIGN_MASK);
}

void
xbranch_direction(ulong_t pc, uchar_t taken)
{
    ulong_t index;
#ifdef STATS
    ++count_branch_direction;
#endif
    index = (pc/BYTES_PER_INST) % BRANCH_PREDICTOR_ENTRIES;
    predictor[index] += taken ? 1 : -1;
    if(predictor[index] > MAX_VALUE) predictor[index] = MAX_VALUE;
    else if(predictor[index] < MIN_VALUE) predictor[index] = MIN_VALUE;
}