gary/vram/MemArbiter_Test.bsv

323 lines
11 KiB
Plaintext

package MemArbiter_Test;
import Assert::*;
import StmtFSM::*;
import Testing::*;
import Printf::*;
import List::*;
import Vector::*;
import BuildVector::*;
import MemArbiter::*;
typedef UInt#(4) Addr;
typedef struct {
String name;
Vector#(n, Maybe#(MemArbiterOp#(Addr))) reqs;
Maybe#(MemArbiterOp#(Addr)) conflict;
Vector#(n, Bool) want_grants;
Maybe#(MemArbiterOp#(Addr)) want_conflict_out;
} TestCase#(numeric type n) deriving (Bits, Eq);
function Maybe#(MemArbiterOp#(Addr)) read(Addr addr);
return tagged Valid MemArbiterOp{write: False, addr: addr};
endfunction
function Maybe#(MemArbiterOp#(Addr)) write(Addr addr);
return tagged Valid MemArbiterOp{write: True, addr: addr};
endfunction
function Maybe#(MemArbiterOp#(Addr)) idle();
return tagged Invalid;
endfunction
function Maybe#(MemArbiterOp#(Addr)) noConflict();
return tagged Invalid;
endfunction
function Vector#(n, Bool) grant(Integer granted);
function gen(idx);
return idx == granted;
endfunction
return genWith(gen);
endfunction
function Vector#(n, Bool) noGrant();
return replicate(False);
endfunction
function TestCase#(n) testCase(String name,
Vector#(n, Maybe#(MemArbiterOp#(Addr))) reqs,
Maybe#(MemArbiterOp#(Addr)) conflict,
Vector#(n, Bool) want_grants,
Maybe#(MemArbiterOp#(Addr)) want_conflict_out);
return TestCase{
name: name,
reqs: reqs,
conflict: conflict,
want_grants: want_grants,
want_conflict_out: want_conflict_out
};
endfunction
interface TB;
method Action start();
(* always_ready *)
method Bool done();
endinterface
module mkArbiterTB(MemArbiter#(n, Addr) dut, Vector#(m, TestCase#(n)) tests, TB ifc);
let testflags <- mkTestFlags();
let cycles <- mkCycleCounter();
Reg#(Bit#(TLog#(m))) idx <- mkReg(0);
Reg#(Bool) running <- mkReg(False);
for (Integer i=0; i<valueOf(n); i=i+1) begin
rule request (running && isValid(tests[idx].reqs[i]));
dut.ports[i].request(validValue(tests[idx].reqs[i]));
endrule
end
(* no_implicit_conditions, fire_when_enabled *)
rule forbid (running && isValid(tests[idx].conflict));
dut.conflict_in(validValue(tests[idx].conflict));
endrule
Wire#(Maybe#(MemArbiterOp#(Addr))) got_conflict_out <- mkDWire(tagged Invalid);
(* fire_when_enabled *)
rule collect_conflict_out (running);
got_conflict_out <= tagged Valid dut.conflict_out();
endrule
function Fmt req_s(Maybe#(MemArbiterOp#(Addr)) v);
case (v) matches
tagged Invalid: return $format("Idle");
tagged Valid .req &&& req.write: return $format("Write(%0d)", req.addr);
tagged Valid .req: return $format("Read(%0d)", req.addr);
endcase
endfunction
(* no_implicit_conditions, fire_when_enabled *)
rule check (running);
let test = tests[idx];
let reqs = test.reqs;
let want_grants = test.want_grants;
let want_conflict_out = test.want_conflict_out;
Vector#(n, Bool) got_grants = newVector;
for (Integer i=0; i<valueOf(n); i=i+1)
got_grants[i] = dut.ports[i].grant();
$display("RUN %s (%0d)", tests[idx].name, idx);
let err = (got_grants != want_grants || got_conflict_out != want_conflict_out);
if (err || testflags.verbose) begin
$display("input:");
for (Integer i=0; i<valueOf(n); i=i+1)
$display(" ", $format("%0d", i), ": ", req_s(reqs[i]));
$display(" conflict: ", fshow(test.conflict));
$display(" output:");
$display(" grants: ", fshow(got_grants));
$display(" granted: ", fshow(got_conflict_out));
$display(" want grants: ", fshow(tests[idx].want_grants));
$display(" want granted: ", fshow(want_conflict_out));
end
dynamicAssert(!err, "wrong arbiter output");
dynamicAssert(cycles == 1, "arbiter took more than 0 cycles");
$display("OK %s", tests[idx].name);
cycles.reset();
if (idx == fromInteger(valueOf(m)-1))
running <= False;
else
idx <= idx+1;
endrule
method Action start() if (!running && idx == 0);
cycles.reset();
running <= True;
endmethod
method Bool done();
return !running && idx != 0;
endmethod
endmodule
module mkTB(Empty);
///////////////////////////////
// Strict arbiter
let strictTests = vec(
// Simple grants
testCase("All idle",
vec(idle, idle, idle), noConflict,
noGrant, noConflict),
testCase("Port 0 read",
vec(read(1), idle, idle), noConflict,
grant(0), read(1)),
testCase("Port 0 write",
vec(write(1), idle, idle), noConflict,
grant(0), write(1)),
testCase("Port 1 read",
vec(idle, read(1), idle), noConflict,
grant(1), read(1)),
testCase("Port 1 write",
vec(idle, write(1), idle), noConflict,
grant(1), write(1)),
testCase("Port 2 read",
vec(idle, idle, read(1)), noConflict,
grant(2), read(1)),
testCase("Port 2 write",
vec(idle, idle, write(1)), noConflict,
grant(2), write(1)),
// Priorities
testCase("Port 0+1",
vec(read(1), read(2), idle), noConflict,
grant(0), read(1)),
testCase("Port 0+2",
vec(read(1), idle, read(2)), noConflict,
grant(0), read(1)),
testCase("Port 1+2",
vec(idle, read(1), read(2)), noConflict,
grant(1), read(1)),
testCase("Port 0+1+2",
vec(read(1), read(2), read(3)), noConflict,
grant(0), read(1)),
testCase("Port 0+1+2, overruled writes",
vec(read(1), write(1), write(2)), noConflict,
grant(0), read(1)),
// Forbidden addrs
testCase("Port 0 read-write denied",
vec(read(1), read(2), idle), write(1),
grant(1), read(2)),
testCase("Port 0 write-write denied",
vec(write(1), read(2), idle), write(1),
grant(1), read(2)),
testCase("Port 0 write-read denied",
vec(write(1), read(2), idle), read(1),
grant(1), read(2)),
testCase("Port 0 no addr match",
vec(write(2), idle, idle), write(1),
grant(0), write(2)),
testCase("Port 0 denied, no alternatives",
vec(write(1), idle, idle), write(1),
noGrant, noConflict)
);
MemArbiter#(3, Addr) strict <- mkPriorityMemArbiter();
let strictTB <- mkArbiterTB(strict, strictTests);
///////////////////////////////
// Round-robin arbiter
let rrTests = vec(
// Simple grants
testCase("All idle",
vec(idle, idle, idle, idle), noConflict,
noGrant, noConflict),
testCase("Port 0 read",
vec(read(1), idle, idle, idle), noConflict,
grant(0), read(1)),
testCase("Port 0 write",
vec(write(1), idle, idle, idle), noConflict,
grant(0), write(1)),
testCase("Port 1 read",
vec(idle, read(1), idle, idle), noConflict,
grant(1), read(1)),
testCase("Port 1 write",
vec(idle, write(1), idle, idle), noConflict,
grant(1), write(1)),
testCase("Port 2 read",
vec(idle, idle, read(1), idle), noConflict,
grant(2), read(1)),
testCase("Port 2 write",
vec(idle, idle, write(1), idle), noConflict,
grant(2), write(1)),
testCase("Port 3 read",
vec(idle, idle, idle, read(1)), noConflict,
grant(3), read(1)),
testCase("Port 3 write",
vec(idle, idle, idle, write(1)), noConflict,
grant(3), write(1)),
// Priorities
testCase("Port 3 to reset RR",
vec(idle, idle, idle, read(1)), noConflict,
grant(3), read(1)),
testCase("Port 0+1 #1",
vec(read(1), read(2), idle, idle), noConflict,
grant(0), read(1)),
testCase("Port 0+1 #2",
vec(read(1), read(2), idle, idle), noConflict,
grant(1), read(2)),
testCase("Port 0+1 #3",
vec(read(1), read(2), idle, idle), noConflict,
grant(0), read(1)),
testCase("Port 0+2 #1",
vec(read(1), idle, read(2), idle), noConflict,
grant(2), read(2)),
testCase("Port 0+2 #2",
vec(read(1), idle, read(2), idle), noConflict,
grant(0), read(1)),
testCase("Port 0+1+2+3 #1",
vec(read(1), read(2), read(3), read(4)), noConflict,
grant(1), read(2)),
testCase("Port 0+1+2+3 #2",
vec(read(1), read(2), read(3), read(4)), noConflict,
grant(2), read(3)),
testCase("Port 0+1+2+3 #3",
vec(read(1), read(2), read(3), read(4)), noConflict,
grant(3), read(4)),
testCase("Port 0+1+2+3 #4",
vec(read(1), read(2), read(3), read(4)), noConflict,
grant(0), read(1)),
testCase("Port 0+1+2+3 #5",
vec(read(1), read(2), read(3), read(4)), noConflict,
grant(1), read(2)),
// Forbidden addrs
testCase("Port 3 to reset RR",
vec(idle, idle, idle, read(1)), noConflict,
grant(3), read(1)),
testCase("RR with denied writes #1",
vec(read(1), write(2), read(3), read(4)), write(3),
grant(0), read(1)),
testCase("RR with denied writes #2",
vec(read(1), write(2), read(3), read(4)), write(3),
grant(1), write(2)),
testCase("RR with denied writes #3",
vec(read(1), write(2), read(3), read(4)), write(3),
grant(3), read(4)),
testCase("RR with denied writes #4",
vec(read(1), write(2), read(3), read(4)), write(3),
grant(0), read(1)),
testCase("RR with denied writes #5",
vec(read(1), write(2), read(3), read(4)), write(3),
grant(1), write(2))
);
MemArbiter#(4, Addr) rr <- mkRoundRobinMemArbiter();
let rrTB <- mkArbiterTB(rr, rrTests);
runTest(100,
mkTest("MemArbiter", seq
mkTest("MemArbiter/Strict", seq
strictTB.start();
await(strictTB.done);
endseq);
mkTest("MemArbiter/RoundRobin", seq
rrTB.start();
await(rrTB.done);
endseq);
endseq));
endmodule
endpackage