#ifndef _sparc_v9_regs_fs
#define _sparc_v9_regs_fs
/******************************************************************************
** FILE: sparc_v9_regs.fs
** Facile description file for the SPARC v.9 registers.
*/

#include "instq.fs"
#include "rename_decode.fs"

#define NWINDOWS	8	// number of architectural register windows
#define NUM_WREGS	128	// total number of registers in windows

//
// Architectural registers

val PC : stream;
val nPC : stream;
val nPC2 : stream;

val CCR = 0?cvt(cc);
val fcc = array(4) { 0?cvt(cc) };

val Y : ulong = 0;

extern get_FSR4() : unsigned[32];
extern get_FSR8() : unsigned[64];
extern set_FSR4(unsigned[32]) : void;
extern set_FSR8(unsigned[64]) : void;

//
// integer registers:

val global_registers = array(7) { 0?ext(64) };
val register_windows = array(NUM_WREGS) { 0?ext(64) };

type cwp_t = unsigned[5];

val CWP		= 0?bits(5);
val CWP0	= 0?bits(5);
val CANSAVE	= (NWINDOWS-2)?bits(5);
val CANRESTORE	= 0?bits(5);
val OTHERWIN	= 0?bits(5);
val CLEANWIN	= (NWINDOWS-1)?bits(5);

fun regs_init(sp) {
    register_windows[14] = sp?sext(64);
}

fun Rx_src(var inst : InstOp, i0) {
    val ii = i0?ext(32);
    if(ii == 0) inst.srcq?push_back(literal_src(0));
    else if(ii < 8) inst.srcq?push_back(rmap_src(REG_GLOBAL,ii-1));
    else {
	val win = (CWP?cvt(ulong) - (ii / 16) + NWINDOWS) % NWINDOWS;
	ii = ii & 0xf?ext(32);
	inst.srcq?push_back(rmap_src(REG_WINDOW,16*win+ii));
    }
}

fun Rx_dest(var inst : InstOp, i0) {
    val ii = i0?ext(32);
    if(ii >= 8) {
	val win = (CWP?cvt(ulong) - (ii / 16) + NWINDOWS) % NWINDOWS;
	ii = ii & 0xf?ext(32);
	inst.destq?push_back(rmap_dest(REG_WINDOW,16*win+ii));
    } else if(ii > 0) {
	inst.destq?push_back(rmap_dest(REG_GLOBAL,ii-1));
    } else {
	val dest : DestRef;
	dest.rtype = REG_LITERAL?cvt(uchar);
	dest.regnum = 0?cvt(uchar);
	inst.destq?push_back(dest);
    }
}

fun R8_src(var inst : InstOp, i0) {
    val ii = i0?ext(32);
    Rx_src(inst,ii);
    Rx_src(inst,ii+1);
}

fun R8_dest(var inst : InstOp, i0) {
    val ii = i0?ext(32);
    Rx_dest(inst,ii);
    Rx_dest(inst,ii+1);
}

//
// floating-point registers:

val fregs = array(64) { 0?ext(32) };

fun F4_src(var inst : InstOp, ii) {
    inst.srcq?push_back(rmap_src(REG_FP,ii));
}

fun F4_dest(var inst : InstOp, ii) {
    inst.destq?push_back(rmap_dest(REG_FP,ii));
}

fun F8_src(var inst : InstOp, i0) {
    val ii = i0?ext(32)&(~1) | (i0?bit(0)?ext(32)<<5);
    F4_src(inst,ii); F4_src(inst,ii+1);
}

fun F8_dest(var inst : InstOp, i0) {
    val ii = i0?ext(32)&(~1) | (i0?bit(0)?ext(32)<<5);
    F4_dest(inst,ii); F4_dest(inst,ii+1);
}

//
// Memory access:

fun M1(a) { return system?memory(1,a)?ext(64); }
fun M1s(a) { return system?memory(1,a)?sext(64); }
fun M1(a,vv) { system?memory(1,a) = vv?cast(unsigned[_])?bits(8); }

fun M2(a) { return system?memory(2,a)?ext(64); }
fun M2s(a) { return system?memory(2,a)?sext(64); }
fun M2(a,vv) { system?memory(2,a) = vv?cast(unsigned[_])?bits(16); }

fun M4(a) { return system?memory(4,a)?ext(64); }
fun M4s(a) { return system?memory(4,a)?sext(64); }
fun M4(a,vv) { system?memory(4,a) = vv?cast(unsigned[_])?bits(32); }

fun M8(a) { return system?memory(8,a); }
fun M8(a,vv) { system?memory(8,a) = vv?cast(unsigned[64]); }

///////////////////////////////////////////////////////////////////////////////
// External functions providing access to processor data structures.
//

extern get_CCR() : cc;
extern set_CCR(cc) : void;
fun get_CCR() : cc { return CCR; }
fun set_CCR(CCR1 : cc) : void { CCR = CCR1; }

extern get_fcc(ulong) : cc;
extern set_fcc(ulong,cc) : void;
fun get_fcc(ii : ulong) : cc { return fcc[ii]; }
fun set_fcc(ii : ulong, CC1 : cc) : void { fcc[ii] = CC1; }

extern get_R4(cwp_t,ulong) : ulong;
extern set_R4(cwp_t,ulong,ulong) : void;

fun get_R4(cwp : cwp_t, i0 : ulong) {
    val ii = i0?ext(32);
    if(ii == 0) return 0?ext(32);
    else if(ii < 8) return global_registers[ii-1]?bits(32);
    else {
	val win = (cwp?cvt(ulong) - (ii / 16) + NWINDOWS) % NWINDOWS;
	ii = ii & 0xf?ext(32); return register_windows[16*win+ii]?bits(32);
    }
}

fun set_R4(cwp : cwp_t, i0 : ulong, vv : ulong) {
    val ii = i0?ext(32);
    if(ii >= 8) {
	val win = (cwp?cvt(ulong) - (ii / 16) + NWINDOWS) % NWINDOWS;
	ii = ii & 0xf?ext(32); register_windows[16*win+ii] = vv?sext(64);
    } else if(ii > 0) {
	global_registers[ii-1] = vv?sext(64);
    }
}

#endif