vram/MemArbiter: fix bug with write conflict avoidance

Now that all arbiter ports can request to write, arbitration must check
both (write, read) and (read, write) conflicts, not just (write, read).
This commit is contained in:
David Anderson 2024-09-08 14:49:54 -07:00
parent 191cd1bfa2
commit 519eddc552
3 changed files with 172 additions and 194 deletions

View File

@ -4,6 +4,7 @@ import MemArbiter::*;
import Vector::*; import Vector::*;
import DReg::*; import DReg::*;
import DelayLine::*; import DelayLine::*;
import Connectable::*;
typedef UInt#(2) Addr; typedef UInt#(2) Addr;
@ -22,70 +23,51 @@ endinterface
(* synthesize, clock_prefix="clk_25mhz", reset_prefix="rst_btn" *) (* synthesize, clock_prefix="clk_25mhz", reset_prefix="rst_btn" *)
module mkTop(Top); module mkTop(Top);
Vector#(2, Reg#(Maybe#(MemArbiterWrite#(Addr)))) wrin <- replicateM(mkDReg(tagged Invalid)); Vector#(6, Reg#(Maybe#(MemArbiterOp#(Addr)))) wrin <- replicateM(mkDReg(tagged Invalid));
Vector#(4, Reg#(Maybe#(Addr))) rdin <- replicateM(mkDReg(tagged Invalid));
MemArbiter#(Addr) ret <- mkMemArbiter(); MemArbiter#(3, Addr) portA <- mkPriorityMemArbiter();
MemArbiter#(3, Addr) portB <- mkRoundRobinMemArbiter();
mkConnection(portA, portB);
let arbiters = append(portA.ports, portB.ports);
Reg#(Vector#(6, Bool)) ok <- mkReg(replicate(False)); Reg#(Vector#(6, Bool)) ok <- mkReg(replicate(False));
rule req_cpu (wrin[0] matches tagged Valid .req); for (Integer i=0; i<6; i=i+1) begin
ret.cpu.request(req); rule req (wrin[i] matches tagged Valid .req);
endrule arbiters[i].request(req);
rule req_debugger (wrin[1] matches tagged Valid .req);
ret.debugger.request(req);
endrule
rule req_palette (rdin[0] matches tagged Valid .addr);
ret.palette.request(addr);
endrule
rule req_tile1 (rdin[1] matches tagged Valid .addr);
ret.tile1.request(addr);
endrule
rule req_tile2 (rdin[2] matches tagged Valid .addr);
ret.tile2.request(addr);
endrule
rule req_sprite (rdin[3] matches tagged Valid .addr);
ret.sprite.request(addr);
endrule endrule
end
rule resp; rule resp;
Vector#(6, Bool) r = newVector; function Bool get(MemArbiterServer#(Addr) s);
r[0] = ret.cpu.grant(); return s.grant();
r[1] = ret.debugger.grant(); endfunction
r[2] = ret.palette.grant(); ok <= map(get, arbiters);
r[3] = ret.tile1.grant();
r[4] = ret.tile2.grant();
r[5] = ret.sprite.grant();
ok <= r;
endrule endrule
method Action cpu(Bool write, Addr addr); method Action cpu(Bool write, Addr addr);
wrin[0] <= tagged Valid MemArbiterWrite{write: write, addr: addr}; wrin[0] <= tagged Valid MemArbiterOp{write: write, addr: addr};
endmethod endmethod
method Action debugger(Bool write, Addr addr); method Action debugger(Bool write, Addr addr);
wrin[1] <= tagged Valid MemArbiterWrite{write: write, addr: addr}; wrin[1] <= tagged Valid MemArbiterOp{write: write, addr: addr};
endmethod endmethod
method Action palette(Addr addr); method Action palette(Addr addr);
rdin[0] <= tagged Valid addr; wrin[2] <= tagged Valid MemArbiterOp{write: False, addr: addr};
endmethod endmethod
method Action tile1(Addr addr); method Action tile1(Addr addr);
rdin[1] <= tagged Valid addr; wrin[3] <= tagged Valid MemArbiterOp{write: False, addr: addr};
endmethod endmethod
method Action tile2(Addr addr); method Action tile2(Addr addr);
rdin[2] <= tagged Valid addr; wrin[4] <= tagged Valid MemArbiterOp{write: False, addr: addr};
endmethod endmethod
method Action sprite(Addr addr); method Action sprite(Addr addr);
rdin[3] <= tagged Valid addr; wrin[5] <= tagged Valid MemArbiterOp{write: False, addr: addr};
endmethod endmethod
method Bit#(6) grants(); method Bit#(6) grants();

View File

@ -15,6 +15,15 @@ typedef struct {
addr addr; addr addr;
} MemArbiterOp#(type addr) deriving (Bits, Eq, FShow); } MemArbiterOp#(type addr) deriving (Bits, Eq, FShow);
function Bool mem_ops_conflict(Maybe#(MemArbiterOp#(addr)) a, Maybe#(MemArbiterOp#(addr)) b)
provisos(Eq#(addr));
if (a matches tagged Valid .ar &&& b matches tagged Valid .br &&& ar.addr == br.addr)
return ar.write || br.write;
else
return False;
endfunction
// A MemArbiterServer receives requests and emits grants. // A MemArbiterServer receives requests and emits grants.
interface MemArbiterServer#(type addr); interface MemArbiterServer#(type addr);
method Action request(MemArbiterOp#(addr) req); method Action request(MemArbiterOp#(addr) req);
@ -54,22 +63,23 @@ interface MemArbiter#(numeric type num_clients, type addr);
// each memory port must cooperate to avoid simultaneously granting // each memory port must cooperate to avoid simultaneously granting
// conflicting requests from their clients. // conflicting requests from their clients.
// //
// Calling forbid_addr prevents the arbiter from granting a // Calling conflict prevents the arbiter from granting a concurrent
// concurrent request to access the given address. forbidden_addr // request that would result in a write-write, read-write or
// emits the address for which a write access is being granted. // write-read conflict. granted_op emits the operation that the
// arbiter is granting, if any.
// //
// MemArbiter intances are Connectable: mkConnection(a, b) gives // MemArbiter intances are Connectable: mkConnection(a, b) gives
// conflict priority to a. That is, b will not grant requests that // conflict priority to a. That is, b only grants requests that
// conflict with the grant that a has emitted. // don't conflict with a's grant.
method Action forbid_addr(addr addr); method Action conflict(MemArbiterOp#(addr) conflict);
method addr forbidden_addr(); method MemArbiterOp#(addr) granted_op();
endinterface endinterface
instance Connectable#(MemArbiter#(m, addr), MemArbiter#(n, addr)); instance Connectable#(MemArbiter#(m, addr), MemArbiter#(n, addr));
module mkConnection(MemArbiter#(m, addr) a, MemArbiter#(n, addr) b, Empty ifc); module mkConnection(MemArbiter#(m, addr) a, MemArbiter#(n, addr) b, Empty ifc);
(* fire_when_enabled *) (* fire_when_enabled *)
rule forward_forbid; rule forward_conflict;
b.forbid_addr(a.forbidden_addr); b.conflict(a.granted_op);
endrule endrule
endmodule endmodule
endinstance endinstance
@ -84,12 +94,8 @@ module mkPriorityMemArbiter(MemArbiter#(num_clients, addr))
Vector#(num_clients, RWire#(MemArbiterOp#(addr))) reqs <- replicateM(mkRWire()); Vector#(num_clients, RWire#(MemArbiterOp#(addr))) reqs <- replicateM(mkRWire());
Wire#(Vector#(num_clients, Bool)) grants <- mkBypassWire(); Wire#(Vector#(num_clients, Bool)) grants <- mkBypassWire();
RWire#(addr) blocked_in <- mkRWire(); RWire#(MemArbiterOp#(addr)) conflict_in <- mkRWire();
RWire#(addr) blocked_out <- mkRWire(); RWire#(MemArbiterOp#(addr)) granted_op_out <- mkRWire();
function Bool is_blocked(addr addr);
return blocked_in.wget() == tagged Valid addr;
endfunction
(* no_implicit_conditions, fire_when_enabled *) (* no_implicit_conditions, fire_when_enabled *)
rule grant_requests; rule grant_requests;
@ -97,11 +103,12 @@ module mkPriorityMemArbiter(MemArbiter#(num_clients, addr))
Bool done = False; Bool done = False;
for (Integer i=0; i<valueOf(num_clients); i=i+1) begin for (Integer i=0; i<valueOf(num_clients); i=i+1) begin
if (reqs[i].wget() matches tagged Valid .req &&& !is_blocked(req.addr) &&& !done) begin if (reqs[i].wget() matches tagged Valid .req &&&
!mem_ops_conflict(conflict_in.wget(), reqs[i].wget()) &&&
!done) begin
done = True; done = True;
grant[i] = True; grant[i] = True;
if (req.write) granted_op_out.wset(req);
blocked_out.wset(req.addr);
end end
end end
@ -116,9 +123,9 @@ module mkPriorityMemArbiter(MemArbiter#(num_clients, addr))
endinterface); endinterface);
interface ports = _ifcs; interface ports = _ifcs;
method forbid_addr = blocked_in.wset; method conflict = conflict_in.wset;
method addr forbidden_addr() if (blocked_out.wget() matches tagged Valid .addr); method MemArbiterOp#(addr) granted_op() if (granted_op_out.wget() matches tagged Valid .op);
return addr; return op;
endmethod endmethod
endmodule endmodule
@ -126,19 +133,15 @@ typedef struct {
Bool granted; Bool granted;
Vector#(n, Bool) grant_vec; Vector#(n, Bool) grant_vec;
UInt#(TLog#(n)) selected; UInt#(TLog#(n)) selected;
Maybe#(addr) blocked_addr; Maybe#(MemArbiterOp#(addr)) granted_op;
} GrantResult#(numeric type n, type addr) deriving (Bits, Eq, FShow); } GrantResult#(numeric type n, type addr) deriving (Bits, Eq, FShow);
// select_grant computes which one entry of requests should be granted. // select_grant computes which one entry of requests should be granted.
function GrantResult#(n, addr) select_grant(Vector#(n, Maybe#(MemArbiterOp#(addr))) requests, function GrantResult#(n, addr) select_grant(Vector#(n, Maybe#(MemArbiterOp#(addr))) requests,
UInt#(TLog#(n)) hipri, UInt#(TLog#(n)) hipri,
Maybe#(addr) block_addr) Maybe#(MemArbiterOp#(addr)) conflict)
provisos (Eq#(addr)); provisos (Eq#(addr));
function is_blocked(addr);
return tagged Valid addr == block_addr;
endfunction
function onehot(idx); function onehot(idx);
let ret = replicate(False); let ret = replicate(False);
ret[idx] = True; ret[idx] = True;
@ -149,12 +152,12 @@ function GrantResult#(n, addr) select_grant(Vector#(n, Maybe#(MemArbiterOp#(addr
Tuple2#(UInt#(TLog#(n)), Tuple2#(UInt#(TLog#(n)),
Maybe#(MemArbiterOp#(addr))) next); Maybe#(MemArbiterOp#(addr))) next);
match {.idx, .mreq} = next; match {.idx, .mreq} = next;
if (mreq matches tagged Valid .req &&& !acc.granted &&& !is_blocked(req.addr)) if (mreq matches tagged Valid .req &&& !acc.granted &&& !mem_ops_conflict(conflict, mreq))
return GrantResult{ return GrantResult{
granted: True, granted: True,
grant_vec: onehot(idx), grant_vec: onehot(idx),
selected: idx, selected: idx,
blocked_addr: req.write ? tagged Valid req.addr : tagged Invalid granted_op: tagged Valid req
}; };
else else
// Previous grant won, not requesting, or request not satisfiable. // Previous grant won, not requesting, or request not satisfiable.
@ -167,7 +170,7 @@ function GrantResult#(n, addr) select_grant(Vector#(n, Maybe#(MemArbiterOp#(addr
granted: False, granted: False,
grant_vec: replicate(False), grant_vec: replicate(False),
selected: 0, selected: 0,
blocked_addr: tagged Invalid granted_op: tagged Invalid
}; };
return foldl(do_fold, seed, rot); return foldl(do_fold, seed, rot);
endfunction endfunction
@ -180,8 +183,8 @@ module mkRoundRobinMemArbiter(MemArbiter#(num_clients, addr))
Vector#(num_clients, RWire#(MemArbiterOp#(addr))) reqs <- replicateM(mkRWire); Vector#(num_clients, RWire#(MemArbiterOp#(addr))) reqs <- replicateM(mkRWire);
Wire#(Vector#(num_clients, Bool)) grants <- mkBypassWire(); Wire#(Vector#(num_clients, Bool)) grants <- mkBypassWire();
RWire#(addr) blocked_in <- mkRWire(); RWire#(MemArbiterOp#(addr)) conflict_in <- mkRWire();
Wire#(Maybe#(addr)) blocked_out <- mkBypassWire(); RWire#(MemArbiterOp#(addr)) granted_op_out <- mkRWire();
// high_prio is the index of the client that should be first in // high_prio is the index of the client that should be first in
// line to receive access. Every time we grant access to a client, // line to receive access. Every time we grant access to a client,
@ -195,7 +198,7 @@ module mkRoundRobinMemArbiter(MemArbiter#(num_clients, addr))
rule grant; rule grant;
let in = map(get_mreq, reqs); let in = map(get_mreq, reqs);
let res = select_grant(in, high_prio, blocked_in.wget()); let res = select_grant(in, high_prio, conflict_in.wget());
grants <= res.grant_vec; grants <= res.grant_vec;
if (res.granted) if (res.granted)
@ -203,7 +206,8 @@ module mkRoundRobinMemArbiter(MemArbiter#(num_clients, addr))
high_prio <= 0; high_prio <= 0;
else else
high_prio <= res.selected+1; high_prio <= res.selected+1;
blocked_out <= res.blocked_addr; if (res.granted_op matches tagged Valid .op)
granted_op_out.wset(op);
endrule endrule
Vector#(num_clients, MemArbiterServer#(addr)) _ifcs = newVector(); Vector#(num_clients, MemArbiterServer#(addr)) _ifcs = newVector();
@ -214,9 +218,9 @@ module mkRoundRobinMemArbiter(MemArbiter#(num_clients, addr))
endinterface); endinterface);
interface ports = _ifcs; interface ports = _ifcs;
method forbid_addr = blocked_in.wset; method conflict = conflict_in.wset;
method addr forbidden_addr() if (blocked_out matches tagged Valid .addr); method MemArbiterOp#(addr) granted_op() if (granted_op_out.wget() matches tagged Valid .op);
return addr; return op;
endmethod endmethod
endmodule endmodule

View File

@ -16,10 +16,10 @@ typedef struct {
String name; String name;
Vector#(n, Maybe#(MemArbiterOp#(Addr))) reqs; Vector#(n, Maybe#(MemArbiterOp#(Addr))) reqs;
Maybe#(Addr) forbid_addr; Maybe#(MemArbiterOp#(Addr)) conflict;
Vector#(n, Bool) want_grants; Vector#(n, Bool) want_grants;
Maybe#(Addr) want_forbid_addr; Maybe#(MemArbiterOp#(Addr)) want_granted_op;
} TestCase#(numeric type n) deriving (Bits, Eq); } TestCase#(numeric type n) deriving (Bits, Eq);
function Maybe#(MemArbiterOp#(Addr)) read(Addr addr); function Maybe#(MemArbiterOp#(Addr)) read(Addr addr);
@ -34,14 +34,10 @@ function Maybe#(MemArbiterOp#(Addr)) idle();
return tagged Invalid; return tagged Invalid;
endfunction endfunction
function Maybe#(Addr) noForbid(); function Maybe#(MemArbiterOp#(Addr)) noConflict();
return tagged Invalid; return tagged Invalid;
endfunction endfunction
function Maybe#(Addr) forbid(Addr a);
return tagged Valid a;
endfunction
function Vector#(n, Bool) grant(Integer granted); function Vector#(n, Bool) grant(Integer granted);
function gen(idx); function gen(idx);
return idx == granted; return idx == granted;
@ -56,15 +52,15 @@ endfunction
function TestCase#(n) testCase(String name, function TestCase#(n) testCase(String name,
Vector#(n, Maybe#(MemArbiterOp#(Addr))) reqs, Vector#(n, Maybe#(MemArbiterOp#(Addr))) reqs,
Maybe#(Addr) forbid_addr, Maybe#(MemArbiterOp#(Addr)) conflict,
Vector#(n, Bool) want_grants, Vector#(n, Bool) want_grants,
Maybe#(Addr) want_forbid_addr); Maybe#(MemArbiterOp#(Addr)) want_granted_op);
return TestCase{ return TestCase{
name: name, name: name,
reqs: reqs, reqs: reqs,
forbid_addr: forbid_addr, conflict: conflict,
want_grants: want_grants, want_grants: want_grants,
want_forbid_addr: want_forbid_addr want_granted_op: want_granted_op
}; };
endfunction endfunction
@ -87,15 +83,15 @@ module mkArbiterTB(MemArbiter#(n, Addr) dut, Vector#(m, TestCase#(n)) tests, TB
end end
(* no_implicit_conditions, fire_when_enabled *) (* no_implicit_conditions, fire_when_enabled *)
rule forbid (running && isValid(tests[idx].forbid_addr)); rule forbid (running && isValid(tests[idx].conflict));
dut.forbid_addr(validValue(tests[idx].forbid_addr)); dut.conflict(validValue(tests[idx].conflict));
endrule endrule
Wire#(Maybe#(Addr)) got_forbid_addr <- mkDWire(tagged Invalid); Wire#(Maybe#(MemArbiterOp#(Addr))) got_granted_op <- mkDWire(tagged Invalid);
(* fire_when_enabled *) (* fire_when_enabled *)
rule collect_forbid (running); rule collect_granted_op (running);
got_forbid_addr <= tagged Valid dut.forbidden_addr(); got_granted_op <= tagged Valid dut.granted_op();
endrule endrule
function Fmt req_s(Maybe#(MemArbiterOp#(Addr)) v); function Fmt req_s(Maybe#(MemArbiterOp#(Addr)) v);
@ -106,36 +102,29 @@ module mkArbiterTB(MemArbiter#(n, Addr) dut, Vector#(m, TestCase#(n)) tests, TB
endcase endcase
endfunction endfunction
function Fmt addr_s(Maybe#(Addr) v);
case (v) matches
tagged Invalid: return $format("<nil>");
tagged Valid .a: return $format("%0d", a);
endcase
endfunction
(* no_implicit_conditions, fire_when_enabled *) (* no_implicit_conditions, fire_when_enabled *)
rule check (running); rule check (running);
let test = tests[idx]; let test = tests[idx];
let reqs = test.reqs; let reqs = test.reqs;
let want_grants = test.want_grants; let want_grants = test.want_grants;
let want_forbid_addr = test.want_forbid_addr; let want_granted_op = test.want_granted_op;
Vector#(n, Bool) got_grants = newVector; Vector#(n, Bool) got_grants = newVector;
for (Integer i=0; i<valueOf(n); i=i+1) for (Integer i=0; i<valueOf(n); i=i+1)
got_grants[i] = dut.ports[i].grant(); got_grants[i] = dut.ports[i].grant();
$display("RUN %s (%0d)", tests[idx].name, idx); $display("RUN %s (%0d)", tests[idx].name, idx);
if (got_grants != want_grants || got_forbid_addr != want_forbid_addr) begin if (got_grants != want_grants || got_granted_op != want_granted_op) begin
$display("input:"); $display("input:");
for (Integer i=0; i<valueOf(n); i=i+1) for (Integer i=0; i<valueOf(n); i=i+1)
$display(" ", $format("%0d", i), ": ", req_s(reqs[i])); $display(" ", $format("%0d", i), ": ", req_s(reqs[i]));
$display(" forbid: ", addr_s(test.forbid_addr)); $display(" conflict: ", fshow(test.conflict));
$display(" output:"); $display(" output:");
$display(" grants: ", fshow(got_grants)); $display(" grants: ", fshow(got_grants));
$display(" forbid: ", addr_s(got_forbid_addr)); $display(" granted: ", fshow(got_granted_op));
$display(" want grants: ", fshow(tests[idx].want_grants)); $display(" want grants: ", fshow(tests[idx].want_grants));
$display(" want forbid: ", addr_s(want_forbid_addr)); $display(" want granted: ", fshow(want_granted_op));
dynamicAssert(False, "wrong arbiter output"); dynamicAssert(False, "wrong arbiter output");
end end
@ -167,57 +156,60 @@ module mkTB(Empty);
let strictTests = vec( let strictTests = vec(
// Simple grants // Simple grants
testCase("All idle", testCase("All idle",
vec(idle, idle, idle), noForbid, vec(idle, idle, idle), noConflict,
noGrant, noForbid), noGrant, noConflict),
testCase("Port 0 read", testCase("Port 0 read",
vec(read(1), idle, idle), noForbid, vec(read(1), idle, idle), noConflict,
grant(0), noForbid), grant(0), read(1)),
testCase("Port 0 write", testCase("Port 0 write",
vec(write(1), idle, idle), noForbid, vec(write(1), idle, idle), noConflict,
grant(0), forbid(1)), grant(0), write(1)),
testCase("Port 1 read", testCase("Port 1 read",
vec(idle, read(1), idle), noForbid, vec(idle, read(1), idle), noConflict,
grant(1), noForbid), grant(1), read(1)),
testCase("Port 1 write", testCase("Port 1 write",
vec(idle, write(1), idle), noForbid, vec(idle, write(1), idle), noConflict,
grant(1), forbid(1)), grant(1), write(1)),
testCase("Port 2 read", testCase("Port 2 read",
vec(idle, idle, read(1)), noForbid, vec(idle, idle, read(1)), noConflict,
grant(2), noForbid), grant(2), read(1)),
testCase("Port 2 write", testCase("Port 2 write",
vec(idle, idle, write(1)), noForbid, vec(idle, idle, write(1)), noConflict,
grant(2), forbid(1)), grant(2), write(1)),
// Priorities // Priorities
testCase("Port 0+1", testCase("Port 0+1",
vec(read(1), read(2), idle), noForbid, vec(read(1), read(2), idle), noConflict,
grant(0), noForbid), grant(0), read(1)),
testCase("Port 0+2", testCase("Port 0+2",
vec(read(1), idle, read(2)), noForbid, vec(read(1), idle, read(2)), noConflict,
grant(0), noForbid), grant(0), read(1)),
testCase("Port 1+2", testCase("Port 1+2",
vec(idle, read(1), read(2)), noForbid, vec(idle, read(1), read(2)), noConflict,
grant(1), noForbid), grant(1), read(1)),
testCase("Port 0+1+2", testCase("Port 0+1+2",
vec(read(1), read(2), read(3)), noForbid, vec(read(1), read(2), read(3)), noConflict,
grant(0), noForbid), grant(0), read(1)),
testCase("Port 0+1+2, overruled writes", testCase("Port 0+1+2, overruled writes",
vec(read(1), write(1), write(2)), noForbid, vec(read(1), write(1), write(2)), noConflict,
grant(0), noForbid), grant(0), read(1)),
// Forbidden addrs // Forbidden addrs
testCase("Port 0 read denied", testCase("Port 0 read-write denied",
vec(read(1), read(2), idle), forbid(1), vec(read(1), read(2), idle), write(1),
grant(1), noForbid), grant(1), read(2)),
testCase("Port 0 write denied", testCase("Port 0 write-write denied",
vec(write(1), read(2), idle), forbid(1), vec(write(1), read(2), idle), write(1),
grant(1), noForbid), 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", testCase("Port 0 no addr match",
vec(write(2), idle, idle), forbid(1), vec(write(2), idle, idle), write(1),
grant(0), forbid(2)), grant(0), write(2)),
testCase("Port 0 denied, no alternatives", testCase("Port 0 denied, no alternatives",
vec(write(1), idle, idle), forbid(1), vec(write(1), idle, idle), write(1),
noGrant, noForbid) noGrant, noConflict)
); );
MemArbiter#(3, Addr) strict <- mkPriorityMemArbiter(); MemArbiter#(3, Addr) strict <- mkPriorityMemArbiter();
let strictTB <- mkArbiterTB(strict, strictTests); let strictTB <- mkArbiterTB(strict, strictTests);
@ -227,87 +219,87 @@ module mkTB(Empty);
let rrTests = vec( let rrTests = vec(
// Simple grants // Simple grants
testCase("All idle", testCase("All idle",
vec(idle, idle, idle, idle), noForbid, vec(idle, idle, idle, idle), noConflict,
noGrant, noForbid), noGrant, noConflict),
testCase("Port 0 read", testCase("Port 0 read",
vec(read(1), idle, idle, idle), noForbid, vec(read(1), idle, idle, idle), noConflict,
grant(0), noForbid), grant(0), read(1)),
testCase("Port 0 write", testCase("Port 0 write",
vec(write(1), idle, idle, idle), noForbid, vec(write(1), idle, idle, idle), noConflict,
grant(0), forbid(1)), grant(0), write(1)),
testCase("Port 1 read", testCase("Port 1 read",
vec(idle, read(1), idle, idle), noForbid, vec(idle, read(1), idle, idle), noConflict,
grant(1), noForbid), grant(1), read(1)),
testCase("Port 1 write", testCase("Port 1 write",
vec(idle, write(1), idle, idle), noForbid, vec(idle, write(1), idle, idle), noConflict,
grant(1), forbid(1)), grant(1), write(1)),
testCase("Port 2 read", testCase("Port 2 read",
vec(idle, idle, read(1), idle), noForbid, vec(idle, idle, read(1), idle), noConflict,
grant(2), noForbid), grant(2), read(1)),
testCase("Port 2 write", testCase("Port 2 write",
vec(idle, idle, write(1), idle), noForbid, vec(idle, idle, write(1), idle), noConflict,
grant(2), forbid(1)), grant(2), write(1)),
testCase("Port 3 read", testCase("Port 3 read",
vec(idle, idle, idle, read(1)), noForbid, vec(idle, idle, idle, read(1)), noConflict,
grant(3), noForbid), grant(3), read(1)),
testCase("Port 3 write", testCase("Port 3 write",
vec(idle, idle, idle, write(1)), noForbid, vec(idle, idle, idle, write(1)), noConflict,
grant(3), forbid(1)), grant(3), write(1)),
// Priorities // Priorities
testCase("Port 3 to reset RR", testCase("Port 3 to reset RR",
vec(idle, idle, idle, read(1)), noForbid, vec(idle, idle, idle, read(1)), noConflict,
grant(3), noForbid), grant(3), read(1)),
testCase("Port 0+1 #1", testCase("Port 0+1 #1",
vec(read(1), read(2), idle, idle), noForbid, vec(read(1), read(2), idle, idle), noConflict,
grant(0), noForbid), grant(0), read(1)),
testCase("Port 0+1 #2", testCase("Port 0+1 #2",
vec(read(1), read(2), idle, idle), noForbid, vec(read(1), read(2), idle, idle), noConflict,
grant(1), noForbid), grant(1), read(2)),
testCase("Port 0+1 #3", testCase("Port 0+1 #3",
vec(read(1), read(2), idle, idle), noForbid, vec(read(1), read(2), idle, idle), noConflict,
grant(0), noForbid), grant(0), read(1)),
testCase("Port 0+2 #1", testCase("Port 0+2 #1",
vec(read(1), idle, read(2), idle), noForbid, vec(read(1), idle, read(2), idle), noConflict,
grant(2), noForbid), grant(2), read(2)),
testCase("Port 0+2 #2", testCase("Port 0+2 #2",
vec(read(1), idle, read(2), idle), noForbid, vec(read(1), idle, read(2), idle), noConflict,
grant(0), noForbid), grant(0), read(1)),
testCase("Port 0+1+2+3 #1", testCase("Port 0+1+2+3 #1",
vec(read(1), read(2), read(3), read(4)), noForbid, vec(read(1), read(2), read(3), read(4)), noConflict,
grant(1), noForbid), grant(1), read(2)),
testCase("Port 0+1+2+3 #2", testCase("Port 0+1+2+3 #2",
vec(read(1), read(2), read(3), read(4)), noForbid, vec(read(1), read(2), read(3), read(4)), noConflict,
grant(2), noForbid), grant(2), read(3)),
testCase("Port 0+1+2+3 #3", testCase("Port 0+1+2+3 #3",
vec(read(1), read(2), read(3), read(4)), noForbid, vec(read(1), read(2), read(3), read(4)), noConflict,
grant(3), noForbid), grant(3), read(4)),
testCase("Port 0+1+2+3 #4", testCase("Port 0+1+2+3 #4",
vec(read(1), read(2), read(3), read(4)), noForbid, vec(read(1), read(2), read(3), read(4)), noConflict,
grant(0), noForbid), grant(0), read(1)),
testCase("Port 0+1+2+3 #5", testCase("Port 0+1+2+3 #5",
vec(read(1), read(2), read(3), read(4)), noForbid, vec(read(1), read(2), read(3), read(4)), noConflict,
grant(1), noForbid), grant(1), read(2)),
// Forbidden addrs // Forbidden addrs
testCase("Port 3 to reset RR", testCase("Port 3 to reset RR",
vec(idle, idle, idle, read(1)), noForbid, vec(idle, idle, idle, read(1)), noConflict,
grant(3), noForbid), grant(3), read(1)),
testCase("RR with denied writes #1", testCase("RR with denied writes #1",
vec(read(1), write(2), read(3), read(4)), forbid(3), vec(read(1), write(2), read(3), read(4)), write(3),
grant(0), noForbid), grant(0), read(1)),
testCase("RR with denied writes #2", testCase("RR with denied writes #2",
vec(read(1), write(2), read(3), read(4)), forbid(3), vec(read(1), write(2), read(3), read(4)), write(3),
grant(1), forbid(2)), grant(1), write(2)),
testCase("RR with denied writes #3", testCase("RR with denied writes #3",
vec(read(1), write(2), read(3), read(4)), forbid(3), vec(read(1), write(2), read(3), read(4)), write(3),
grant(3), noForbid), grant(3), read(4)),
testCase("RR with denied writes #4", testCase("RR with denied writes #4",
vec(read(1), write(2), read(3), read(4)), forbid(3), vec(read(1), write(2), read(3), read(4)), write(3),
grant(0), noForbid), grant(0), read(1)),
testCase("RR with denied writes #5", testCase("RR with denied writes #5",
vec(read(1), write(2), read(3), read(4)), forbid(3), vec(read(1), write(2), read(3), read(4)), write(3),
grant(1), forbid(2)) grant(1), write(2))
); );
MemArbiter#(4, Addr) rr <- mkRoundRobinMemArbiter(); MemArbiter#(4, Addr) rr <- mkRoundRobinMemArbiter();
let rrTB <- mkArbiterTB(rr, rrTests); let rrTB <- mkArbiterTB(rr, rrTests);