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:
parent
191cd1bfa2
commit
519eddc552
|
@ -4,6 +4,7 @@ import MemArbiter::*;
|
|||
import Vector::*;
|
||||
import DReg::*;
|
||||
import DelayLine::*;
|
||||
import Connectable::*;
|
||||
|
||||
typedef UInt#(2) Addr;
|
||||
|
||||
|
@ -22,70 +23,51 @@ endinterface
|
|||
|
||||
(* synthesize, clock_prefix="clk_25mhz", reset_prefix="rst_btn" *)
|
||||
module mkTop(Top);
|
||||
Vector#(2, Reg#(Maybe#(MemArbiterWrite#(Addr)))) wrin <- replicateM(mkDReg(tagged Invalid));
|
||||
Vector#(4, Reg#(Maybe#(Addr))) rdin <- replicateM(mkDReg(tagged Invalid));
|
||||
Vector#(6, Reg#(Maybe#(MemArbiterOp#(Addr)))) wrin <- 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));
|
||||
|
||||
rule req_cpu (wrin[0] matches tagged Valid .req);
|
||||
ret.cpu.request(req);
|
||||
endrule
|
||||
|
||||
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);
|
||||
for (Integer i=0; i<6; i=i+1) begin
|
||||
rule req (wrin[i] matches tagged Valid .req);
|
||||
arbiters[i].request(req);
|
||||
endrule
|
||||
end
|
||||
|
||||
rule resp;
|
||||
Vector#(6, Bool) r = newVector;
|
||||
r[0] = ret.cpu.grant();
|
||||
r[1] = ret.debugger.grant();
|
||||
r[2] = ret.palette.grant();
|
||||
r[3] = ret.tile1.grant();
|
||||
r[4] = ret.tile2.grant();
|
||||
r[5] = ret.sprite.grant();
|
||||
ok <= r;
|
||||
function Bool get(MemArbiterServer#(Addr) s);
|
||||
return s.grant();
|
||||
endfunction
|
||||
ok <= map(get, arbiters);
|
||||
endrule
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
method Action palette(Addr addr);
|
||||
rdin[0] <= tagged Valid addr;
|
||||
wrin[2] <= tagged Valid MemArbiterOp{write: False, addr: addr};
|
||||
endmethod
|
||||
|
||||
method Action tile1(Addr addr);
|
||||
rdin[1] <= tagged Valid addr;
|
||||
wrin[3] <= tagged Valid MemArbiterOp{write: False, addr: addr};
|
||||
endmethod
|
||||
|
||||
method Action tile2(Addr addr);
|
||||
rdin[2] <= tagged Valid addr;
|
||||
wrin[4] <= tagged Valid MemArbiterOp{write: False, addr: addr};
|
||||
endmethod
|
||||
|
||||
method Action sprite(Addr addr);
|
||||
rdin[3] <= tagged Valid addr;
|
||||
wrin[5] <= tagged Valid MemArbiterOp{write: False, addr: addr};
|
||||
endmethod
|
||||
|
||||
method Bit#(6) grants();
|
||||
|
|
|
@ -15,6 +15,15 @@ typedef struct {
|
|||
addr addr;
|
||||
} 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.
|
||||
interface MemArbiterServer#(type addr);
|
||||
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
|
||||
// conflicting requests from their clients.
|
||||
//
|
||||
// Calling forbid_addr prevents the arbiter from granting a
|
||||
// concurrent request to access the given address. forbidden_addr
|
||||
// emits the address for which a write access is being granted.
|
||||
// Calling conflict prevents the arbiter from granting a concurrent
|
||||
// request that would result in a write-write, read-write or
|
||||
// write-read conflict. granted_op emits the operation that the
|
||||
// arbiter is granting, if any.
|
||||
//
|
||||
// MemArbiter intances are Connectable: mkConnection(a, b) gives
|
||||
// conflict priority to a. That is, b will not grant requests that
|
||||
// conflict with the grant that a has emitted.
|
||||
method Action forbid_addr(addr addr);
|
||||
method addr forbidden_addr();
|
||||
// conflict priority to a. That is, b only grants requests that
|
||||
// don't conflict with a's grant.
|
||||
method Action conflict(MemArbiterOp#(addr) conflict);
|
||||
method MemArbiterOp#(addr) granted_op();
|
||||
endinterface
|
||||
|
||||
instance Connectable#(MemArbiter#(m, addr), MemArbiter#(n, addr));
|
||||
module mkConnection(MemArbiter#(m, addr) a, MemArbiter#(n, addr) b, Empty ifc);
|
||||
(* fire_when_enabled *)
|
||||
rule forward_forbid;
|
||||
b.forbid_addr(a.forbidden_addr);
|
||||
rule forward_conflict;
|
||||
b.conflict(a.granted_op);
|
||||
endrule
|
||||
endmodule
|
||||
endinstance
|
||||
|
@ -84,12 +94,8 @@ module mkPriorityMemArbiter(MemArbiter#(num_clients, addr))
|
|||
Vector#(num_clients, RWire#(MemArbiterOp#(addr))) reqs <- replicateM(mkRWire());
|
||||
Wire#(Vector#(num_clients, Bool)) grants <- mkBypassWire();
|
||||
|
||||
RWire#(addr) blocked_in <- mkRWire();
|
||||
RWire#(addr) blocked_out <- mkRWire();
|
||||
|
||||
function Bool is_blocked(addr addr);
|
||||
return blocked_in.wget() == tagged Valid addr;
|
||||
endfunction
|
||||
RWire#(MemArbiterOp#(addr)) conflict_in <- mkRWire();
|
||||
RWire#(MemArbiterOp#(addr)) granted_op_out <- mkRWire();
|
||||
|
||||
(* no_implicit_conditions, fire_when_enabled *)
|
||||
rule grant_requests;
|
||||
|
@ -97,11 +103,12 @@ module mkPriorityMemArbiter(MemArbiter#(num_clients, addr))
|
|||
Bool done = False;
|
||||
|
||||
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;
|
||||
grant[i] = True;
|
||||
if (req.write)
|
||||
blocked_out.wset(req.addr);
|
||||
granted_op_out.wset(req);
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -116,9 +123,9 @@ module mkPriorityMemArbiter(MemArbiter#(num_clients, addr))
|
|||
endinterface);
|
||||
|
||||
interface ports = _ifcs;
|
||||
method forbid_addr = blocked_in.wset;
|
||||
method addr forbidden_addr() if (blocked_out.wget() matches tagged Valid .addr);
|
||||
return addr;
|
||||
method conflict = conflict_in.wset;
|
||||
method MemArbiterOp#(addr) granted_op() if (granted_op_out.wget() matches tagged Valid .op);
|
||||
return op;
|
||||
endmethod
|
||||
endmodule
|
||||
|
||||
|
@ -126,19 +133,15 @@ typedef struct {
|
|||
Bool granted;
|
||||
Vector#(n, Bool) grant_vec;
|
||||
UInt#(TLog#(n)) selected;
|
||||
Maybe#(addr) blocked_addr;
|
||||
Maybe#(MemArbiterOp#(addr)) granted_op;
|
||||
} GrantResult#(numeric type n, type addr) deriving (Bits, Eq, FShow);
|
||||
|
||||
// select_grant computes which one entry of requests should be granted.
|
||||
function GrantResult#(n, addr) select_grant(Vector#(n, Maybe#(MemArbiterOp#(addr))) requests,
|
||||
UInt#(TLog#(n)) hipri,
|
||||
Maybe#(addr) block_addr)
|
||||
Maybe#(MemArbiterOp#(addr)) conflict)
|
||||
provisos (Eq#(addr));
|
||||
|
||||
function is_blocked(addr);
|
||||
return tagged Valid addr == block_addr;
|
||||
endfunction
|
||||
|
||||
function onehot(idx);
|
||||
let ret = replicate(False);
|
||||
ret[idx] = True;
|
||||
|
@ -149,12 +152,12 @@ function GrantResult#(n, addr) select_grant(Vector#(n, Maybe#(MemArbiterOp#(addr
|
|||
Tuple2#(UInt#(TLog#(n)),
|
||||
Maybe#(MemArbiterOp#(addr))) 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{
|
||||
granted: True,
|
||||
grant_vec: onehot(idx),
|
||||
selected: idx,
|
||||
blocked_addr: req.write ? tagged Valid req.addr : tagged Invalid
|
||||
granted_op: tagged Valid req
|
||||
};
|
||||
else
|
||||
// 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,
|
||||
grant_vec: replicate(False),
|
||||
selected: 0,
|
||||
blocked_addr: tagged Invalid
|
||||
granted_op: tagged Invalid
|
||||
};
|
||||
return foldl(do_fold, seed, rot);
|
||||
endfunction
|
||||
|
@ -180,8 +183,8 @@ module mkRoundRobinMemArbiter(MemArbiter#(num_clients, addr))
|
|||
Vector#(num_clients, RWire#(MemArbiterOp#(addr))) reqs <- replicateM(mkRWire);
|
||||
Wire#(Vector#(num_clients, Bool)) grants <- mkBypassWire();
|
||||
|
||||
RWire#(addr) blocked_in <- mkRWire();
|
||||
Wire#(Maybe#(addr)) blocked_out <- mkBypassWire();
|
||||
RWire#(MemArbiterOp#(addr)) conflict_in <- mkRWire();
|
||||
RWire#(MemArbiterOp#(addr)) granted_op_out <- mkRWire();
|
||||
|
||||
// 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,
|
||||
|
@ -195,7 +198,7 @@ module mkRoundRobinMemArbiter(MemArbiter#(num_clients, addr))
|
|||
|
||||
rule grant;
|
||||
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;
|
||||
if (res.granted)
|
||||
|
@ -203,7 +206,8 @@ module mkRoundRobinMemArbiter(MemArbiter#(num_clients, addr))
|
|||
high_prio <= 0;
|
||||
else
|
||||
high_prio <= res.selected+1;
|
||||
blocked_out <= res.blocked_addr;
|
||||
if (res.granted_op matches tagged Valid .op)
|
||||
granted_op_out.wset(op);
|
||||
endrule
|
||||
|
||||
Vector#(num_clients, MemArbiterServer#(addr)) _ifcs = newVector();
|
||||
|
@ -214,9 +218,9 @@ module mkRoundRobinMemArbiter(MemArbiter#(num_clients, addr))
|
|||
endinterface);
|
||||
|
||||
interface ports = _ifcs;
|
||||
method forbid_addr = blocked_in.wset;
|
||||
method addr forbidden_addr() if (blocked_out matches tagged Valid .addr);
|
||||
return addr;
|
||||
method conflict = conflict_in.wset;
|
||||
method MemArbiterOp#(addr) granted_op() if (granted_op_out.wget() matches tagged Valid .op);
|
||||
return op;
|
||||
endmethod
|
||||
endmodule
|
||||
|
||||
|
|
|
@ -16,10 +16,10 @@ typedef struct {
|
|||
String name;
|
||||
|
||||
Vector#(n, Maybe#(MemArbiterOp#(Addr))) reqs;
|
||||
Maybe#(Addr) forbid_addr;
|
||||
Maybe#(MemArbiterOp#(Addr)) conflict;
|
||||
|
||||
Vector#(n, Bool) want_grants;
|
||||
Maybe#(Addr) want_forbid_addr;
|
||||
Maybe#(MemArbiterOp#(Addr)) want_granted_op;
|
||||
} TestCase#(numeric type n) deriving (Bits, Eq);
|
||||
|
||||
function Maybe#(MemArbiterOp#(Addr)) read(Addr addr);
|
||||
|
@ -34,14 +34,10 @@ function Maybe#(MemArbiterOp#(Addr)) idle();
|
|||
return tagged Invalid;
|
||||
endfunction
|
||||
|
||||
function Maybe#(Addr) noForbid();
|
||||
function Maybe#(MemArbiterOp#(Addr)) noConflict();
|
||||
return tagged Invalid;
|
||||
endfunction
|
||||
|
||||
function Maybe#(Addr) forbid(Addr a);
|
||||
return tagged Valid a;
|
||||
endfunction
|
||||
|
||||
function Vector#(n, Bool) grant(Integer granted);
|
||||
function gen(idx);
|
||||
return idx == granted;
|
||||
|
@ -56,15 +52,15 @@ endfunction
|
|||
|
||||
function TestCase#(n) testCase(String name,
|
||||
Vector#(n, Maybe#(MemArbiterOp#(Addr))) reqs,
|
||||
Maybe#(Addr) forbid_addr,
|
||||
Maybe#(MemArbiterOp#(Addr)) conflict,
|
||||
Vector#(n, Bool) want_grants,
|
||||
Maybe#(Addr) want_forbid_addr);
|
||||
Maybe#(MemArbiterOp#(Addr)) want_granted_op);
|
||||
return TestCase{
|
||||
name: name,
|
||||
reqs: reqs,
|
||||
forbid_addr: forbid_addr,
|
||||
conflict: conflict,
|
||||
want_grants: want_grants,
|
||||
want_forbid_addr: want_forbid_addr
|
||||
want_granted_op: want_granted_op
|
||||
};
|
||||
endfunction
|
||||
|
||||
|
@ -87,15 +83,15 @@ module mkArbiterTB(MemArbiter#(n, Addr) dut, Vector#(m, TestCase#(n)) tests, TB
|
|||
end
|
||||
|
||||
(* no_implicit_conditions, fire_when_enabled *)
|
||||
rule forbid (running && isValid(tests[idx].forbid_addr));
|
||||
dut.forbid_addr(validValue(tests[idx].forbid_addr));
|
||||
rule forbid (running && isValid(tests[idx].conflict));
|
||||
dut.conflict(validValue(tests[idx].conflict));
|
||||
endrule
|
||||
|
||||
Wire#(Maybe#(Addr)) got_forbid_addr <- mkDWire(tagged Invalid);
|
||||
Wire#(Maybe#(MemArbiterOp#(Addr))) got_granted_op <- mkDWire(tagged Invalid);
|
||||
|
||||
(* fire_when_enabled *)
|
||||
rule collect_forbid (running);
|
||||
got_forbid_addr <= tagged Valid dut.forbidden_addr();
|
||||
rule collect_granted_op (running);
|
||||
got_granted_op <= tagged Valid dut.granted_op();
|
||||
endrule
|
||||
|
||||
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
|
||||
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 *)
|
||||
rule check (running);
|
||||
let test = tests[idx];
|
||||
let reqs = test.reqs;
|
||||
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;
|
||||
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);
|
||||
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:");
|
||||
for (Integer i=0; i<valueOf(n); i=i+1)
|
||||
$display(" ", $format("%0d", i), ": ", req_s(reqs[i]));
|
||||
$display(" forbid: ", addr_s(test.forbid_addr));
|
||||
$display(" conflict: ", fshow(test.conflict));
|
||||
|
||||
$display(" output:");
|
||||
$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 forbid: ", addr_s(want_forbid_addr));
|
||||
$display(" want granted: ", fshow(want_granted_op));
|
||||
dynamicAssert(False, "wrong arbiter output");
|
||||
end
|
||||
|
||||
|
@ -167,57 +156,60 @@ module mkTB(Empty);
|
|||
let strictTests = vec(
|
||||
// Simple grants
|
||||
testCase("All idle",
|
||||
vec(idle, idle, idle), noForbid,
|
||||
noGrant, noForbid),
|
||||
vec(idle, idle, idle), noConflict,
|
||||
noGrant, noConflict),
|
||||
testCase("Port 0 read",
|
||||
vec(read(1), idle, idle), noForbid,
|
||||
grant(0), noForbid),
|
||||
vec(read(1), idle, idle), noConflict,
|
||||
grant(0), read(1)),
|
||||
testCase("Port 0 write",
|
||||
vec(write(1), idle, idle), noForbid,
|
||||
grant(0), forbid(1)),
|
||||
vec(write(1), idle, idle), noConflict,
|
||||
grant(0), write(1)),
|
||||
testCase("Port 1 read",
|
||||
vec(idle, read(1), idle), noForbid,
|
||||
grant(1), noForbid),
|
||||
vec(idle, read(1), idle), noConflict,
|
||||
grant(1), read(1)),
|
||||
testCase("Port 1 write",
|
||||
vec(idle, write(1), idle), noForbid,
|
||||
grant(1), forbid(1)),
|
||||
vec(idle, write(1), idle), noConflict,
|
||||
grant(1), write(1)),
|
||||
testCase("Port 2 read",
|
||||
vec(idle, idle, read(1)), noForbid,
|
||||
grant(2), noForbid),
|
||||
vec(idle, idle, read(1)), noConflict,
|
||||
grant(2), read(1)),
|
||||
testCase("Port 2 write",
|
||||
vec(idle, idle, write(1)), noForbid,
|
||||
grant(2), forbid(1)),
|
||||
vec(idle, idle, write(1)), noConflict,
|
||||
grant(2), write(1)),
|
||||
|
||||
// Priorities
|
||||
testCase("Port 0+1",
|
||||
vec(read(1), read(2), idle), noForbid,
|
||||
grant(0), noForbid),
|
||||
vec(read(1), read(2), idle), noConflict,
|
||||
grant(0), read(1)),
|
||||
testCase("Port 0+2",
|
||||
vec(read(1), idle, read(2)), noForbid,
|
||||
grant(0), noForbid),
|
||||
vec(read(1), idle, read(2)), noConflict,
|
||||
grant(0), read(1)),
|
||||
testCase("Port 1+2",
|
||||
vec(idle, read(1), read(2)), noForbid,
|
||||
grant(1), noForbid),
|
||||
vec(idle, read(1), read(2)), noConflict,
|
||||
grant(1), read(1)),
|
||||
testCase("Port 0+1+2",
|
||||
vec(read(1), read(2), read(3)), noForbid,
|
||||
grant(0), noForbid),
|
||||
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)), noForbid,
|
||||
grant(0), noForbid),
|
||||
vec(read(1), write(1), write(2)), noConflict,
|
||||
grant(0), read(1)),
|
||||
|
||||
// Forbidden addrs
|
||||
testCase("Port 0 read denied",
|
||||
vec(read(1), read(2), idle), forbid(1),
|
||||
grant(1), noForbid),
|
||||
testCase("Port 0 write denied",
|
||||
vec(write(1), read(2), idle), forbid(1),
|
||||
grant(1), noForbid),
|
||||
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), forbid(1),
|
||||
grant(0), forbid(2)),
|
||||
vec(write(2), idle, idle), write(1),
|
||||
grant(0), write(2)),
|
||||
testCase("Port 0 denied, no alternatives",
|
||||
vec(write(1), idle, idle), forbid(1),
|
||||
noGrant, noForbid)
|
||||
vec(write(1), idle, idle), write(1),
|
||||
noGrant, noConflict)
|
||||
);
|
||||
MemArbiter#(3, Addr) strict <- mkPriorityMemArbiter();
|
||||
let strictTB <- mkArbiterTB(strict, strictTests);
|
||||
|
@ -227,87 +219,87 @@ module mkTB(Empty);
|
|||
let rrTests = vec(
|
||||
// Simple grants
|
||||
testCase("All idle",
|
||||
vec(idle, idle, idle, idle), noForbid,
|
||||
noGrant, noForbid),
|
||||
vec(idle, idle, idle, idle), noConflict,
|
||||
noGrant, noConflict),
|
||||
testCase("Port 0 read",
|
||||
vec(read(1), idle, idle, idle), noForbid,
|
||||
grant(0), noForbid),
|
||||
vec(read(1), idle, idle, idle), noConflict,
|
||||
grant(0), read(1)),
|
||||
testCase("Port 0 write",
|
||||
vec(write(1), idle, idle, idle), noForbid,
|
||||
grant(0), forbid(1)),
|
||||
vec(write(1), idle, idle, idle), noConflict,
|
||||
grant(0), write(1)),
|
||||
testCase("Port 1 read",
|
||||
vec(idle, read(1), idle, idle), noForbid,
|
||||
grant(1), noForbid),
|
||||
vec(idle, read(1), idle, idle), noConflict,
|
||||
grant(1), read(1)),
|
||||
testCase("Port 1 write",
|
||||
vec(idle, write(1), idle, idle), noForbid,
|
||||
grant(1), forbid(1)),
|
||||
vec(idle, write(1), idle, idle), noConflict,
|
||||
grant(1), write(1)),
|
||||
testCase("Port 2 read",
|
||||
vec(idle, idle, read(1), idle), noForbid,
|
||||
grant(2), noForbid),
|
||||
vec(idle, idle, read(1), idle), noConflict,
|
||||
grant(2), read(1)),
|
||||
testCase("Port 2 write",
|
||||
vec(idle, idle, write(1), idle), noForbid,
|
||||
grant(2), forbid(1)),
|
||||
vec(idle, idle, write(1), idle), noConflict,
|
||||
grant(2), write(1)),
|
||||
testCase("Port 3 read",
|
||||
vec(idle, idle, idle, read(1)), noForbid,
|
||||
grant(3), noForbid),
|
||||
vec(idle, idle, idle, read(1)), noConflict,
|
||||
grant(3), read(1)),
|
||||
testCase("Port 3 write",
|
||||
vec(idle, idle, idle, write(1)), noForbid,
|
||||
grant(3), forbid(1)),
|
||||
vec(idle, idle, idle, write(1)), noConflict,
|
||||
grant(3), write(1)),
|
||||
|
||||
// Priorities
|
||||
testCase("Port 3 to reset RR",
|
||||
vec(idle, idle, idle, read(1)), noForbid,
|
||||
grant(3), noForbid),
|
||||
vec(idle, idle, idle, read(1)), noConflict,
|
||||
grant(3), read(1)),
|
||||
testCase("Port 0+1 #1",
|
||||
vec(read(1), read(2), idle, idle), noForbid,
|
||||
grant(0), noForbid),
|
||||
vec(read(1), read(2), idle, idle), noConflict,
|
||||
grant(0), read(1)),
|
||||
testCase("Port 0+1 #2",
|
||||
vec(read(1), read(2), idle, idle), noForbid,
|
||||
grant(1), noForbid),
|
||||
vec(read(1), read(2), idle, idle), noConflict,
|
||||
grant(1), read(2)),
|
||||
testCase("Port 0+1 #3",
|
||||
vec(read(1), read(2), idle, idle), noForbid,
|
||||
grant(0), noForbid),
|
||||
vec(read(1), read(2), idle, idle), noConflict,
|
||||
grant(0), read(1)),
|
||||
testCase("Port 0+2 #1",
|
||||
vec(read(1), idle, read(2), idle), noForbid,
|
||||
grant(2), noForbid),
|
||||
vec(read(1), idle, read(2), idle), noConflict,
|
||||
grant(2), read(2)),
|
||||
testCase("Port 0+2 #2",
|
||||
vec(read(1), idle, read(2), idle), noForbid,
|
||||
grant(0), noForbid),
|
||||
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)), noForbid,
|
||||
grant(1), noForbid),
|
||||
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)), noForbid,
|
||||
grant(2), noForbid),
|
||||
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)), noForbid,
|
||||
grant(3), noForbid),
|
||||
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)), noForbid,
|
||||
grant(0), noForbid),
|
||||
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)), noForbid,
|
||||
grant(1), noForbid),
|
||||
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)), noForbid,
|
||||
grant(3), noForbid),
|
||||
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)), forbid(3),
|
||||
grant(0), noForbid),
|
||||
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)), forbid(3),
|
||||
grant(1), forbid(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)), forbid(3),
|
||||
grant(3), noForbid),
|
||||
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)), forbid(3),
|
||||
grant(0), noForbid),
|
||||
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)), forbid(3),
|
||||
grant(1), forbid(2))
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue