2024-08-31 22:25:04 +02:00
|
|
|
package MemArbiter_Test;
|
2024-08-31 22:25:04 +02:00
|
|
|
|
|
|
|
import Assert::*;
|
|
|
|
import StmtFSM::*;
|
|
|
|
import Testing::*;
|
|
|
|
import Printf::*;
|
|
|
|
import List::*;
|
|
|
|
import Vector::*;
|
|
|
|
import BuildVector::*;
|
|
|
|
|
2024-08-31 22:25:04 +02:00
|
|
|
import MemArbiter::*;
|
2024-08-31 22:25:04 +02:00
|
|
|
|
|
|
|
typedef UInt#(4) Addr;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
String name;
|
2024-09-08 20:42:35 +02:00
|
|
|
|
|
|
|
Vector#(n, Maybe#(MemArbiterOp#(Addr))) reqs;
|
2024-09-08 23:49:54 +02:00
|
|
|
Maybe#(MemArbiterOp#(Addr)) conflict;
|
2024-09-08 20:42:35 +02:00
|
|
|
|
|
|
|
Vector#(n, Bool) want_grants;
|
2024-09-08 18:26:59 +02:00
|
|
|
Maybe#(MemArbiterOp#(Addr)) want_conflict_out;
|
2024-09-08 20:42:35 +02:00
|
|
|
} TestCase#(numeric type n) deriving (Bits, Eq);
|
|
|
|
|
|
|
|
function Maybe#(MemArbiterOp#(Addr)) read(Addr addr);
|
|
|
|
return tagged Valid MemArbiterOp{write: False, addr: addr};
|
2024-08-31 22:25:04 +02:00
|
|
|
endfunction
|
|
|
|
|
2024-09-08 20:42:35 +02:00
|
|
|
function Maybe#(MemArbiterOp#(Addr)) write(Addr addr);
|
|
|
|
return tagged Valid MemArbiterOp{write: True, addr: addr};
|
2024-08-31 22:25:04 +02:00
|
|
|
endfunction
|
|
|
|
|
2024-09-08 20:42:35 +02:00
|
|
|
function Maybe#(MemArbiterOp#(Addr)) idle();
|
|
|
|
return tagged Invalid;
|
2024-08-31 22:25:04 +02:00
|
|
|
endfunction
|
|
|
|
|
2024-09-08 23:49:54 +02:00
|
|
|
function Maybe#(MemArbiterOp#(Addr)) noConflict();
|
2024-08-31 22:25:04 +02:00
|
|
|
return tagged Invalid;
|
|
|
|
endfunction
|
|
|
|
|
2024-09-08 20:42:35 +02:00
|
|
|
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);
|
2024-08-31 22:25:04 +02:00
|
|
|
endfunction
|
|
|
|
|
2024-09-08 20:42:35 +02:00
|
|
|
function TestCase#(n) testCase(String name,
|
|
|
|
Vector#(n, Maybe#(MemArbiterOp#(Addr))) reqs,
|
2024-09-08 23:49:54 +02:00
|
|
|
Maybe#(MemArbiterOp#(Addr)) conflict,
|
2024-09-08 20:42:35 +02:00
|
|
|
Vector#(n, Bool) want_grants,
|
2024-09-08 18:26:59 +02:00
|
|
|
Maybe#(MemArbiterOp#(Addr)) want_conflict_out);
|
2024-08-31 22:25:04 +02:00
|
|
|
return TestCase{
|
|
|
|
name: name,
|
2024-09-08 20:42:35 +02:00
|
|
|
reqs: reqs,
|
2024-09-08 23:49:54 +02:00
|
|
|
conflict: conflict,
|
2024-09-08 20:42:35 +02:00
|
|
|
want_grants: want_grants,
|
2024-09-08 18:26:59 +02:00
|
|
|
want_conflict_out: want_conflict_out
|
2024-08-31 22:25:04 +02:00
|
|
|
};
|
|
|
|
endfunction
|
|
|
|
|
2024-09-08 20:42:35 +02:00
|
|
|
interface TB;
|
|
|
|
method Action start();
|
|
|
|
(* always_ready *)
|
|
|
|
method Bool done();
|
|
|
|
endinterface
|
2024-08-31 22:25:04 +02:00
|
|
|
|
2024-09-08 20:42:35 +02:00
|
|
|
module mkArbiterTB(MemArbiter#(n, Addr) dut, Vector#(m, TestCase#(n)) tests, TB ifc);
|
|
|
|
let cycles <- mkCycleCounter();
|
2024-08-31 22:25:04 +02:00
|
|
|
|
2024-09-08 20:42:35 +02:00
|
|
|
Reg#(Bit#(TLog#(m))) idx <- mkReg(0);
|
|
|
|
Reg#(Bool) running <- mkReg(False);
|
2024-08-31 22:25:04 +02:00
|
|
|
|
2024-09-08 20:42:35 +02:00
|
|
|
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
|
2024-08-31 22:25:04 +02:00
|
|
|
|
|
|
|
(* no_implicit_conditions, fire_when_enabled *)
|
2024-09-08 23:49:54 +02:00
|
|
|
rule forbid (running && isValid(tests[idx].conflict));
|
2024-09-08 18:26:59 +02:00
|
|
|
dut.conflict_in(validValue(tests[idx].conflict));
|
2024-08-31 22:25:04 +02:00
|
|
|
endrule
|
|
|
|
|
2024-09-08 18:26:59 +02:00
|
|
|
Wire#(Maybe#(MemArbiterOp#(Addr))) got_conflict_out <- mkDWire(tagged Invalid);
|
2024-08-31 22:25:04 +02:00
|
|
|
|
2024-09-08 20:42:35 +02:00
|
|
|
(* fire_when_enabled *)
|
2024-09-08 18:26:59 +02:00
|
|
|
rule collect_conflict_out (running);
|
|
|
|
got_conflict_out <= tagged Valid dut.conflict_out();
|
2024-08-31 22:25:04 +02:00
|
|
|
endrule
|
|
|
|
|
2024-09-08 20:42:35 +02:00
|
|
|
function Fmt req_s(Maybe#(MemArbiterOp#(Addr)) v);
|
2024-08-31 22:25:04 +02:00
|
|
|
case (v) matches
|
2024-09-08 20:42:35 +02:00
|
|
|
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);
|
2024-08-31 22:25:04 +02:00
|
|
|
endcase
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
(* no_implicit_conditions, fire_when_enabled *)
|
2024-09-08 20:42:35 +02:00
|
|
|
rule check (running);
|
2024-08-31 22:25:04 +02:00
|
|
|
let test = tests[idx];
|
2024-09-08 20:42:35 +02:00
|
|
|
let reqs = test.reqs;
|
|
|
|
let want_grants = test.want_grants;
|
2024-09-08 18:26:59 +02:00
|
|
|
let want_conflict_out = test.want_conflict_out;
|
2024-09-08 20:42:35 +02:00
|
|
|
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);
|
2024-09-08 18:26:59 +02:00
|
|
|
if (got_grants != want_grants || got_conflict_out != want_conflict_out) begin
|
2024-09-08 22:31:53 +02:00
|
|
|
$display("input:");
|
2024-09-08 20:42:35 +02:00
|
|
|
for (Integer i=0; i<valueOf(n); i=i+1)
|
|
|
|
$display(" ", $format("%0d", i), ": ", req_s(reqs[i]));
|
2024-09-08 23:49:54 +02:00
|
|
|
$display(" conflict: ", fshow(test.conflict));
|
2024-09-08 20:42:35 +02:00
|
|
|
|
|
|
|
$display(" output:");
|
|
|
|
$display(" grants: ", fshow(got_grants));
|
2024-09-08 18:26:59 +02:00
|
|
|
$display(" granted: ", fshow(got_conflict_out));
|
2024-09-08 20:42:35 +02:00
|
|
|
|
|
|
|
$display(" want grants: ", fshow(tests[idx].want_grants));
|
2024-09-08 18:26:59 +02:00
|
|
|
$display(" want granted: ", fshow(want_conflict_out));
|
2024-09-08 20:42:35 +02:00
|
|
|
dynamicAssert(False, "wrong arbiter output");
|
2024-08-31 22:25:04 +02:00
|
|
|
end
|
2024-08-31 22:25:04 +02:00
|
|
|
|
2024-09-08 20:42:35 +02:00
|
|
|
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;
|
2024-08-31 22:25:04 +02:00
|
|
|
else
|
2024-09-08 20:42:35 +02:00
|
|
|
idx <= idx+1;
|
2024-08-31 22:25:04 +02:00
|
|
|
endrule
|
2024-09-08 20:42:35 +02:00
|
|
|
|
|
|
|
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",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(idle, idle, idle), noConflict,
|
|
|
|
noGrant, noConflict),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 0 read",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), idle, idle), noConflict,
|
|
|
|
grant(0), read(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 0 write",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(write(1), idle, idle), noConflict,
|
|
|
|
grant(0), write(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 1 read",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(idle, read(1), idle), noConflict,
|
|
|
|
grant(1), read(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 1 write",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(idle, write(1), idle), noConflict,
|
|
|
|
grant(1), write(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 2 read",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(idle, idle, read(1)), noConflict,
|
|
|
|
grant(2), read(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 2 write",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(idle, idle, write(1)), noConflict,
|
|
|
|
grant(2), write(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
|
|
|
|
// Priorities
|
|
|
|
testCase("Port 0+1",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), read(2), idle), noConflict,
|
|
|
|
grant(0), read(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 0+2",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), idle, read(2)), noConflict,
|
|
|
|
grant(0), read(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 1+2",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(idle, read(1), read(2)), noConflict,
|
|
|
|
grant(1), read(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 0+1+2",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), read(2), read(3)), noConflict,
|
|
|
|
grant(0), read(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 0+1+2, overruled writes",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), write(1), write(2)), noConflict,
|
|
|
|
grant(0), read(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
|
|
|
|
// Forbidden addrs
|
2024-09-08 23:49:54 +02:00
|
|
|
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)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 0 no addr match",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(write(2), idle, idle), write(1),
|
|
|
|
grant(0), write(2)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 0 denied, no alternatives",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(write(1), idle, idle), write(1),
|
|
|
|
noGrant, noConflict)
|
2024-09-08 20:42:35 +02:00
|
|
|
);
|
|
|
|
MemArbiter#(3, Addr) strict <- mkPriorityMemArbiter();
|
|
|
|
let strictTB <- mkArbiterTB(strict, strictTests);
|
|
|
|
|
|
|
|
///////////////////////////////
|
|
|
|
// Round-robin arbiter
|
|
|
|
let rrTests = vec(
|
|
|
|
// Simple grants
|
|
|
|
testCase("All idle",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(idle, idle, idle, idle), noConflict,
|
|
|
|
noGrant, noConflict),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 0 read",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), idle, idle, idle), noConflict,
|
|
|
|
grant(0), read(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 0 write",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(write(1), idle, idle, idle), noConflict,
|
|
|
|
grant(0), write(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 1 read",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(idle, read(1), idle, idle), noConflict,
|
|
|
|
grant(1), read(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 1 write",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(idle, write(1), idle, idle), noConflict,
|
|
|
|
grant(1), write(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 2 read",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(idle, idle, read(1), idle), noConflict,
|
|
|
|
grant(2), read(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 2 write",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(idle, idle, write(1), idle), noConflict,
|
|
|
|
grant(2), write(1)),
|
2024-09-08 22:31:53 +02:00
|
|
|
testCase("Port 3 read",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(idle, idle, idle, read(1)), noConflict,
|
|
|
|
grant(3), read(1)),
|
2024-09-08 22:31:53 +02:00
|
|
|
testCase("Port 3 write",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(idle, idle, idle, write(1)), noConflict,
|
|
|
|
grant(3), write(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
|
|
|
|
// Priorities
|
2024-09-08 22:31:53 +02:00
|
|
|
testCase("Port 3 to reset RR",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(idle, idle, idle, read(1)), noConflict,
|
|
|
|
grant(3), read(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 0+1 #1",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), read(2), idle, idle), noConflict,
|
|
|
|
grant(0), read(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 0+1 #2",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), read(2), idle, idle), noConflict,
|
|
|
|
grant(1), read(2)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 0+1 #3",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), read(2), idle, idle), noConflict,
|
|
|
|
grant(0), read(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 0+2 #1",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), idle, read(2), idle), noConflict,
|
|
|
|
grant(2), read(2)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("Port 0+2 #2",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), idle, read(2), idle), noConflict,
|
|
|
|
grant(0), read(1)),
|
2024-09-08 22:31:53 +02:00
|
|
|
testCase("Port 0+1+2+3 #1",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), read(2), read(3), read(4)), noConflict,
|
|
|
|
grant(1), read(2)),
|
2024-09-08 22:31:53 +02:00
|
|
|
testCase("Port 0+1+2+3 #2",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), read(2), read(3), read(4)), noConflict,
|
|
|
|
grant(2), read(3)),
|
2024-09-08 22:31:53 +02:00
|
|
|
testCase("Port 0+1+2+3 #3",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), read(2), read(3), read(4)), noConflict,
|
|
|
|
grant(3), read(4)),
|
2024-09-08 22:31:53 +02:00
|
|
|
testCase("Port 0+1+2+3 #4",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), read(2), read(3), read(4)), noConflict,
|
|
|
|
grant(0), read(1)),
|
2024-09-08 22:31:53 +02:00
|
|
|
testCase("Port 0+1+2+3 #5",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), read(2), read(3), read(4)), noConflict,
|
|
|
|
grant(1), read(2)),
|
2024-09-08 20:42:35 +02:00
|
|
|
|
|
|
|
// Forbidden addrs
|
2024-09-08 22:31:53 +02:00
|
|
|
testCase("Port 3 to reset RR",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(idle, idle, idle, read(1)), noConflict,
|
|
|
|
grant(3), read(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("RR with denied writes #1",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), write(2), read(3), read(4)), write(3),
|
|
|
|
grant(0), read(1)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("RR with denied writes #2",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), write(2), read(3), read(4)), write(3),
|
|
|
|
grant(1), write(2)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("RR with denied writes #3",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), write(2), read(3), read(4)), write(3),
|
|
|
|
grant(3), read(4)),
|
2024-09-08 20:42:35 +02:00
|
|
|
testCase("RR with denied writes #4",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), write(2), read(3), read(4)), write(3),
|
|
|
|
grant(0), read(1)),
|
2024-09-08 22:31:53 +02:00
|
|
|
testCase("RR with denied writes #5",
|
2024-09-08 23:49:54 +02:00
|
|
|
vec(read(1), write(2), read(3), read(4)), write(3),
|
|
|
|
grant(1), write(2))
|
2024-09-08 20:42:35 +02:00
|
|
|
);
|
2024-09-08 22:31:53 +02:00
|
|
|
MemArbiter#(4, Addr) rr <- mkRoundRobinMemArbiter();
|
2024-09-08 20:42:35 +02:00
|
|
|
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));
|
2024-08-31 22:25:04 +02:00
|
|
|
endmodule
|
|
|
|
|
|
|
|
endpackage
|