#ifndef _funits_fs
#define _funits_fs
/******************************************************************************
** FILE: funits.fs
** Manage function units in the OOO processor model.
*/
#include "param.h"
#include "instq.fs"
#include "funits.h"
#include "cache.fs"
///////////////////////////////////////////////////////////////////////////////
// Limit the number of each type of functional units.
// fu_alloc() -- try to allocate one of the functional units
// fu_clear() -- free all allocated units
//
const val fu_pool = array(FU_END1) {
0, // FU_NONE
2, // FU_ALU: 2 dyintegers ALUs
2, // FU_FPU: 2 floating-point units
1 // FU_ADDR: 1 address adder
};
val fu_num_allocated = array(FU_END1) { 0 };
fun fu_alloc(ftype)
{
assert(ftype?cvt(ulong) < FU_END);
if(ftype?cvt(ulong) >= FU_END1) return true;
if(fu_num_allocated[ftype] >= fu_pool[ftype])
return false;
fu_num_allocated[ftype] = fu_num_allocated[ftype] + 1;
return true;
}
fun fu_clear()
{
fu_num_allocated = array(FU_END1) { 0 };
}
///////////////////////////////////////////////////////////////////////////////
// fu_finish() -- called when the timer runs out on an instruction that has
// been assigned a function unit. This means that the instruction is finished
// with the function unit and is ready to move on.
// Returns true if the instruction is ready to execute (in the execute()
// function). Otherwise returns false.
//
fun fu_finish(ftype, var inst : InstOp, inum)
{
switch(ftype?cvt(ulong)) {
case FU_ALU: return true;
case FU_FPU: return true;
case FU_ADDR:
val op = inst.op?cvt(ulong);
val va = (rmap_read(inst.srcq[+0],inum) +
rmap_read(inst.srcq[+1],inum))?cvt(ulong);
val delay : short;
assert(inst.align <= 3?cvt(uchar));
if((va & ((1<<inst.align?cvt(ulong))-1)) != 0) {
if(inum > 0) {
inst.ftime = 1?cvt(uchar);
return false;
}
}
// Unknown store address => no more loads or stores
if(unk_store_addr) { inst.ftime = 1?cvt(uchar); return false; }
if(OP_LOAD_BEGIN <= op && op <= OP_LOAD_END) {
if(cache_load_start(inum,va,no_loads,delay))
return true; // HIT
delay?static;
if(delay >= 0?cvt(short)) {
inst.ftype = FU_LOAD?cvt(uchar); // MISS
inst.ftime = delay?cvt(uchar);
} else {
// cache access aborted
inst.ftime = (-delay)?cvt(uchar);
unk_load_addr = true;
}
} else if(OP_STORE_BEGIN <= op && op <= OP_STORE_END) {
// Unknown load address => store must issue speculatively
if(cache_store_start(inum,va,is_spec||unk_load_addr,delay)) {
// Successful hand-off to cache
delay?static;
assert(delay >= 0?cvt(short));
if(!is_spec && !unk_load_addr && delay == 0?cvt(short)) {
// This store committed
inst.ftype = FU_NONE?cvt(uchar);
return true;
} else {
// This store still needs to be committed
inst.ftype = FU_STORE?cvt(uchar);
if(delay == 0?cvt(short))
inst.ftime = 1?cvt(uchar);
else {
assert(delay > 0?cvt(short));
inst.ftime = delay?cvt(uchar);
}
}
} else {
// cache access aborted
delay?static;
assert(delay < 0?cvt(short));
inst.ftime = (-delay)?cvt(uchar);
unk_store_addr = true;
}
} else {
assert(OP_SWAP_BEGIN <= op && op <= OP_SWAP_END);
// Unknown load address => store must issue speculatively
if(cache_store_start(inum,va,is_spec||unk_load_addr,delay)) {
// Successful hand-off to cache
delay?static;
assert(delay >= 0?cvt(short));
if(!is_spec && !unk_load_addr && delay == 0?cvt(short)) {
// This store committed
inst.ftype = FU_NONE?cvt(uchar);
return true;
} else {
// This store still needs to be committed
inst.ftype = FU_STORE?cvt(uchar);
if(delay == 0?cvt(short))
inst.ftime = 1?cvt(uchar);
else {
assert(delay > 0?cvt(short));
inst.ftime = delay?cvt(uchar);
}
}
} else {
// Cache access aborted
delay?static;
assert(delay < 0?cvt(short));
inst.ftime = (-delay)?cvt(uchar);
unk_store_addr = true;
}
}
case FU_LOAD:
val delay : short;
if(cache_load_continue(inum, delay)) return true;
inst.ftime = delay?static?cvt(uchar);
case FU_STORE:
if(!is_spec && !unk_load_addr) {
val delay : short;
if(cache_store_commit(inum,delay)) {
// This store committed
inst.ftype = FU_NONE?cvt(uchar);
return true;
} else {
// Conflicts still exist => try again later
delay?static;
assert(delay > 0?cvt(short));
inst.ftime = delay?cvt(uchar);
}
} else inst.ftime = 1?cvt(uchar);
default:
// Unexpected ftype
assert(false);
}
return false;
}
#endif