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 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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue