#ifndef __pipeline_fs
#define __pipeline_fs
/******************************************************************************
** FILE: pipeline.fs
** In-order pipeline simulation using reservation tables.
*/
extern cache_load(ulong) : ulong;
extern cache_store(ulong) : ulong;
extern instructions : ullong;
val instructions = 0?cvt(ullong);
extern cycles : ullong;
val cycles = 0?cvt(ullong);
#define NONE 0x00
#define ALU1 0x04
#define ALU2 0x08
#define FPU 0x10
#define LOAD 0x20
#define STORE 0x40
type Pipe = struct {
resources : uchar queue,
instructions : struct {
ready : uchar,
dest : ushort
} queue
};
val pipe : Pipe = struct { resources = queue{}, instructions = queue{} };
type InstInfo1 = struct { reserve : uchar array[2], ready : uchar };
val _alu1_1 = struct { reserve = array { ALU1, NONE }, ready = 1?cvt(uchar) };
val _alu1_2 = struct { reserve = array { NONE, ALU1 }, ready = 2?cvt(uchar) };
val _alu2_1 = struct { reserve = array { ALU2, NONE }, ready = 1?cvt(uchar) };
val _alu2_2 = struct { reserve = array { NONE, ALU2 }, ready = 2?cvt(uchar) };
val _fpu = struct { reserve = array { FPU, FPU }, ready = 2?cvt(uchar) };
val _load1 = struct { reserve = array { ALU1, LOAD }, ready = 2?cvt(uchar) };
val _load2 = struct { reserve = array { ALU2, LOAD }, ready = 2?cvt(uchar) };
val _store1 = struct { reserve = array { ALU1, STORE }, ready = 0?cvt(uchar) };
val _store2 = struct { reserve = array { ALU2, STORE }, ready = 0?cvt(uchar) };
type InstInfo = InstInfo1 queue;
const val alu : InstInfo = queue { _alu1_1, _alu1_2, _alu2_1, _alu2_2 };
const val fpu : InstInfo = queue { _fpu };
const val load : InstInfo = queue { _load1, _load2 };
const val store :InstInfo = queue { _store1, _store2 };
val srcQ : ushort queue = queue {};
val storeQ : ushort queue = queue {};
val destQ : ushort queue = queue {};
val address = 0;
fun ready(var reserve : uchar array[2])
{
val ii = 0;
while(ii < 2) {
val funit = reserve[ii];
if(ii < pipe.resources?length)
if((funit & pipe.resources[+ii]) != 0?cvt(uchar))
return false;
if(funit & (ALU1|ALU2|FPU) != 0?cvt(uchar)) {
val jj = 0;
while(jj < pipe.instructions?length) {
var old = pipe.instructions[+jj];
val kk = 0;
while(kk < srcQ?length) {
if(srcQ[+kk] == old.dest)
if(old.ready > 0?cvt(uchar)) return false;
kk = kk + 1;
}
jj = jj + 1;
}
} else if(funit == STORE) {
val jj = 0;
while(jj < pipe.instructions?length) {
var old = pipe.instructions[+jj];
val kk = 0;
while(kk < storeQ?length) {
if(storeQ[+kk] == old.dest)
if(old.ready > 0?cvt(uchar)) return false;
kk = kk + 1;
}
jj = jj + 1;
}
}
ii = ii + 1;
}
return true;
}
fun update_pipe(var inst1 : InstInfo1)
{
val ready = inst1.ready?cvt(ulong);
val ii = 0;
while(ii < 2) {
val funit = inst1.reserve[ii];
if(ii < pipe.resources?length) {
var funits = pipe.resources[+ii];
funits = funits | funit;
} else
pipe.resources?push_back(funit);
val delay = 0;
if(funit == LOAD)
delay = cache_load(address)?static();
else if(funit == STORE)
delay = cache_store(address)?static();
val jj = 0;
while(jj < delay) {
ii = ii + 1;
if(ready > 0) ready = ready + 1;
if(ii < pipe.resources?length) {
var funits = pipe.resources[+ii];
funits = funits | funit;
} else
pipe.resources?push_back(funit);
jj = jj + 1;
}
ii = ii + 1;
}
if(ready > 0) {
ii = 0;
while(ii < destQ?length) {
pipe.instructions?push_back(struct { ready = ready?cvt(uchar),
dest = destQ[+ii] });
ii = ii + 1;
}
}
}
fun delay_pipe()
{
pipe.resources?pop_front();
val ii = 0;
val new_first = 0;
while(ii < pipe.instructions?length) {
var inst = pipe.instructions[+ii];
if(inst.ready > 0?cvt(uchar)) inst.ready = inst.ready - 1?cvt(uchar);
if(inst.ready > 0?cvt(uchar) && new_first <= 0) new_first = ii;
ii = ii + 1;
}
pipe.instructions?pop_front(new_first?cvt(uchar));
cycles = cycles + 1?cvt(ullong);
}
fun schedule(var inst : InstInfo)
{
while(true) {
val ii = 0;
while(ii < inst?length) {
if(ready(inst[+ii].reserve)) {
update_pipe(inst[+ii]);
return;
}
ii = ii + 1;
}
delay_pipe();
}
}
#endif