/******************************************************************************
** FILE: sparc_v9_reg.fs
** Facile description file for the SPARC v.9 registers.
*/

#include "pipeline.fs"

#define NWINDOWS 8

val PC = 0?cvt(stream);			// program counter
val nPC = 0?cvt(stream);		// next program counter
val nPC2 = 0?cvt(stream);		// next next program counter

val CCR = 0?cvt(cc);			// integer condition codes
val fcc = array(4) { 0?cvt(cc) };	// FP condition codes

val Y : ulong = 0;			// Y register for multiply & divide

// Floating status register (implemented externally)
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(NWINDOWS) { array(16) { 0?ext(64) } };

type cwp_t = unsigned[5];

val CWP		= 0?bits(5);		// current window pointer
val CANSAVE	= (NWINDOWS-2)?bits(5);
val CANRESTORE	= 0?bits(5);
val OTHERWIN	= 0?bits(5);
val CLEANWIN	= (NWINDOWS-1)?bits(5);

fun Rx(i0, var Q : ushort queue) {	// get 64-bit register value
    val ii = i0?ext(32);
    if(ii == 0) return 0?ext(64);
    else if(ii < 8) {
	Q?push_back(ii?cvt(ushort));
	return global_registers[ii-1];
    } else {
	val win = (CWP?cvt(ulong) - (ii / 16) + NWINDOWS) % NWINDOWS;
	ii = ii & 0xf?ext(32);
	Q?push_back((16*win+ii?cvt(ulong)+8)?cvt(ushort));
	return register_windows[win][ii];
    }
}
fun Rx(i0) { return Rx(i0,srcQ); }

fun Rx(i0,vv) {				// set 64-bit register value
    val ii = i0?ext(32);
    if(ii >= 8) {
	val win = (CWP?cvt(ulong) - (ii / 16) + NWINDOWS) % NWINDOWS;
	ii = ii & 0xf?ext(32);
	destQ?push_back((16*win+ii?cvt(ulong)+8)?cvt(ushort));
	register_windows[win][ii] = vv;
    } else if(ii > 0) {
	destQ?push_back(ii?cvt(ushort));
	global_registers[ii-1] = vv;
    }
}

fun R4(ii,var Q) { return Rx(ii,Q)?bits(32); }	// get 32-bit register value
fun R4(ii) { return R4(ii,srcQ); }

fun R4(ii,vv) { Rx(ii, vv?sext(64)); }		// set 32-bit register value

fun R8(i0,var Q) {	// make a 64-bit value from two 32-bit register
    val ii = i0?ext(32);
    val xx = (Rx(ii,Q) & 0xffffffff?ext(64)) << 32;
    return xx | (Rx(ii+1,Q) & 0xffffffff?ext(64));
}
fun R8(i0) { return R8(i0,srcQ); }

fun R8(i0,vv) {		// set two 32-bit registers from a 64 bit value
    val ii = i0?ext(32);
    Rx(ii, vv >> 32);
    Rx(ii+1, vv & 0xffffffff?ext(64));
}

//
// floating-point registers:

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

fun F4(ii, var Q : ushort queue) {
    Q?push_back(ii?cvt(ushort) + 256?cvt(ushort));
    return fregs[ii]?cast(float);
}
fun F4(ii) { return F4(ii,srcQ); }

fun F4(ii,vv) {
    destQ?push_back(ii?cvt(ushort) + 256?cvt(ushort));
    fregs[ii] = vv?cast(unsigned[_])?cvt(ulong);
}

// get concatination of two 32-bit fp-registers
fun F8(i0, var Q : ushort queue) {
    val ii = i0?ext(32)&(~1) | (i0?bit(0)?ext(32)<<5);
    Q?push_back(ii?cvt(ushort) + 256?cvt(ushort));
    Q?push_back(ii?cvt(ushort) + 257?cvt(ushort));
    val xx = fregs[ii]?ext(64) << 32;
    return (xx | fregs[ii+1]?ext(64))?cast(double);
}
fun F8(i0) { return F8(i0,srcQ); }

// set two 32-bit fp-registers
fun F8(i0, vv) {
    val ii = i0?ext(32)&(~1) | (i0?bit(0)?ext(32)<<5);
    destQ?push_back(ii?cvt(ushort) + 256?cvt(ushort));
    destQ?push_back(ii?cvt(ushort) + 257?cvt(ushort));
    fregs[ii] = vv?cast(unsigned[64])?bits(32,63);
    fregs[ii+1] = vv?cast(unsigned[64])?bits(32);
}

//
// 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[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[win][ii] = vv?sext(64);
    } else if(ii > 0) {
	global_registers[ii-1] = vv?sext(64);
    }
}