311 lines
9.4 KiB
Plaintext
311 lines
9.4 KiB
Plaintext
package MemoryArbiter_Test;
|
|
|
|
import Assert::*;
|
|
import StmtFSM::*;
|
|
import Testing::*;
|
|
import Printf::*;
|
|
import List::*;
|
|
import Vector::*;
|
|
import BuildVector::*;
|
|
|
|
import MemoryArbiter::*;
|
|
|
|
typedef UInt#(4) Addr;
|
|
|
|
typedef struct {
|
|
Bool write;
|
|
Addr addr;
|
|
} WriteReq deriving (Bits, Eq);
|
|
|
|
typedef struct {
|
|
String name;
|
|
Maybe#(WriteReq) cpu;
|
|
Maybe#(WriteReq) debugger;
|
|
Maybe#(Addr) palette;
|
|
Maybe#(Addr) tile1;
|
|
Maybe#(Addr) tile2;
|
|
Maybe#(Addr) sprite;
|
|
|
|
Vector#(6, Bool) want;
|
|
} TestCase deriving (Bits, Eq);
|
|
|
|
function Maybe#(WriteReq) rwRead(Addr addr);
|
|
return tagged Valid WriteReq{write: False, addr: addr};
|
|
endfunction
|
|
|
|
function Maybe#(WriteReq) rwWrite(Addr addr);
|
|
return tagged Valid WriteReq{write: True, addr: addr};
|
|
endfunction
|
|
|
|
function Maybe#(Addr) read(Addr addr);
|
|
return tagged Valid addr;
|
|
endfunction
|
|
|
|
function Maybe#(t) idle();
|
|
return tagged Invalid;
|
|
endfunction
|
|
|
|
function Vector#(6, Bool) grant(Integer granted_a, Integer granted_b);
|
|
let ret = replicate(False);
|
|
if (granted_a >= 0)
|
|
ret[granted_a] = True;
|
|
if (granted_b >= 0)
|
|
ret[granted_b+3] = True;
|
|
return ret;
|
|
endfunction
|
|
|
|
function TestCase testCase(String name,
|
|
Maybe#(WriteReq) cpu,
|
|
Maybe#(WriteReq) debugger,
|
|
Maybe#(Addr) palette,
|
|
Maybe#(Addr) tile1,
|
|
Maybe#(Addr) tile2,
|
|
Maybe#(Addr) sprite,
|
|
Integer portA,
|
|
Integer portB);
|
|
return TestCase{
|
|
name: name,
|
|
cpu: cpu,
|
|
debugger: debugger,
|
|
palette: palette,
|
|
tile1: tile1,
|
|
tile2: tile2,
|
|
sprite: sprite,
|
|
want: grant(portA, portB)
|
|
};
|
|
endfunction
|
|
|
|
module mkTB();
|
|
MemoryArbiter#(Addr) dut <- mkMemoryArbiter();
|
|
|
|
Vector#(26, TestCase) tests = vec(
|
|
testCase("All idle",
|
|
idle, idle, idle,
|
|
idle, idle, idle,
|
|
-1, -1),
|
|
|
|
// Single client accesses at a time
|
|
testCase("CPU read", rwRead(1), idle, idle,
|
|
idle, idle, idle,
|
|
0, -1),
|
|
testCase("CPU write", rwWrite(1), idle, idle,
|
|
idle, idle, idle,
|
|
0, -1),
|
|
testCase("Debugger read",
|
|
idle, rwRead(1), idle,
|
|
idle, idle, idle,
|
|
1, -1),
|
|
testCase("Debugger write",
|
|
idle, rwWrite(1), idle,
|
|
idle, idle, idle,
|
|
1, -1),
|
|
testCase("Palette read",
|
|
idle, idle, read(1),
|
|
idle, idle, idle,
|
|
2, -1),
|
|
testCase("Tile1 read",
|
|
idle, idle, idle,
|
|
read(1), idle, idle,
|
|
-1, 0),
|
|
testCase("Tile2 read",
|
|
idle, idle, idle,
|
|
idle, read(1), idle,
|
|
-1, 1),
|
|
testCase("Sprite read",
|
|
idle, idle, idle,
|
|
idle, idle, read(1),
|
|
-1, 2),
|
|
|
|
// Strict priority on port A
|
|
testCase("CPU + Debugger + Palette",
|
|
rwRead(1), rwRead(2), read(3),
|
|
idle, idle, idle,
|
|
0, -1),
|
|
testCase("CPU + Palette",
|
|
rwRead(1), idle, read(3),
|
|
idle, idle, idle,
|
|
0, -1),
|
|
testCase("Debugger + Palette",
|
|
idle, rwRead(2), read(3),
|
|
idle, idle, idle,
|
|
1, -1),
|
|
|
|
// Round-robin on port B
|
|
testCase("Sprite read", // to reset round robin
|
|
idle, idle, idle,
|
|
idle, idle, read(1),
|
|
-1, 2),
|
|
testCase("Tile1 + Tile2 + Sprite",
|
|
idle, idle, idle,
|
|
read(1), read(2), read(3),
|
|
-1, 0),
|
|
testCase("Tile1 + Tile2 + Sprite",
|
|
idle, idle, idle,
|
|
read(1), read(2), read(3),
|
|
-1, 1),
|
|
testCase("Tile1 + Tile2 + Sprite",
|
|
idle, idle, idle,
|
|
read(1), read(2), read(3),
|
|
-1, 2),
|
|
testCase("Tile1 + Tile2 + Sprite",
|
|
idle, idle, idle,
|
|
read(1), read(2), read(3),
|
|
-1, 0),
|
|
testCase("Tile1 + Sprite",
|
|
idle, idle, idle,
|
|
read(1), idle, read(3),
|
|
-1, 2),
|
|
testCase("Tile2 + Sprite",
|
|
idle, idle, idle,
|
|
idle, read(2), read(3),
|
|
-1, 1),
|
|
testCase("Tile2 + Sprite",
|
|
idle, idle, idle,
|
|
idle, read(2), read(3),
|
|
-1, 2),
|
|
|
|
testCase("Read/read, no conflict",
|
|
rwRead(0), idle, idle,
|
|
read(0), idle, idle,
|
|
0, 0),
|
|
testCase("Write/read, no conflict",
|
|
rwWrite(1), idle, idle,
|
|
read(0), idle, idle,
|
|
0, 0),
|
|
testCase("Tile1 write conflict",
|
|
rwWrite(0), idle, idle,
|
|
read(0), idle, idle,
|
|
0, -1),
|
|
testCase("Tile2 write conflict",
|
|
rwWrite(0), idle, idle,
|
|
idle, read(0), idle,
|
|
0, -1),
|
|
testCase("Sprite write conflict",
|
|
rwWrite(0), idle, idle,
|
|
idle, idle, read(0),
|
|
0, -1),
|
|
testCase("Tile1 write conflict with debugger",
|
|
idle, rwWrite(0), idle,
|
|
read(0), idle, idle,
|
|
1, -1)
|
|
|
|
);
|
|
|
|
Reg#(UInt#(32)) idx <- mkReg(0);
|
|
|
|
rule display_test (idx == 0);
|
|
$display("RUN TestMemoryArbiter");
|
|
endrule
|
|
|
|
(* no_implicit_conditions, fire_when_enabled *)
|
|
rule input_cpu (tests[idx].cpu matches tagged Valid .req &&& req matches WriteReq {write: .write, addr: .addr});
|
|
dut.cpu.request(write, addr);
|
|
endrule
|
|
|
|
(* no_implicit_conditions, fire_when_enabled *)
|
|
rule input_debugger (tests[idx].debugger matches tagged Valid .req &&& req matches WriteReq {write: .write, addr: .addr});
|
|
dut.debugger.request(write, addr);
|
|
endrule
|
|
|
|
(* no_implicit_conditions, fire_when_enabled *)
|
|
rule input_palette (tests[idx].palette matches tagged Valid .addr);
|
|
dut.palette.request(addr);
|
|
endrule
|
|
|
|
(* no_implicit_conditions, fire_when_enabled *)
|
|
rule input_tile1 (tests[idx].tile1 matches tagged Valid .addr);
|
|
dut.tile1.request(addr);
|
|
endrule
|
|
|
|
(* no_implicit_conditions, fire_when_enabled *)
|
|
rule input_tile2 (tests[idx].tile2 matches tagged Valid .addr);
|
|
dut.tile2.request(addr);
|
|
endrule
|
|
|
|
(* no_implicit_conditions, fire_when_enabled *)
|
|
rule input_sprite (tests[idx].sprite matches tagged Valid .addr);
|
|
dut.sprite.request(addr);
|
|
endrule
|
|
|
|
function Fmt rw_str(Maybe#(WriteReq) v);
|
|
case (v) matches
|
|
tagged Valid .req: begin
|
|
if (req.write)
|
|
return $format("Write(%0d)", req.addr);
|
|
else
|
|
return $format("Read(%0d)", req.addr);
|
|
end
|
|
tagged Invalid: return $format("Idle");
|
|
endcase
|
|
endfunction
|
|
|
|
function Fmt ro_str(Maybe#(Addr) v);
|
|
case (v) matches
|
|
tagged Valid .addr: return $format("Read(%0d)", addr);
|
|
tagged Invalid: return $format("Idle");
|
|
endcase
|
|
endfunction
|
|
|
|
(* no_implicit_conditions, fire_when_enabled *)
|
|
rule check_grants;
|
|
Vector#(6, Bool) gotVec = newVector;
|
|
gotVec[0] = dut.cpu.grant();
|
|
gotVec[1] = dut.debugger.grant();
|
|
gotVec[2] = dut.palette.grant();
|
|
gotVec[3] = dut.tile1.grant();
|
|
gotVec[4] = dut.tile2.grant();
|
|
gotVec[5] = dut.sprite.grant();
|
|
|
|
let test = tests[idx];
|
|
let got = pack(reverse(gotVec));
|
|
let want = pack(reverse(test.want));
|
|
|
|
$display("\n # %0d: %s", idx+1, tests[idx].name);
|
|
$display(" input:",
|
|
"\n 0:", rw_str(test.cpu), "\n 1:", rw_str(test.debugger), "\n 2:", ro_str(test.palette),
|
|
"\n 3:", ro_str(test.tile1), "\n 4:", ro_str(test.tile2), "\n 5:", ro_str(test.sprite));
|
|
$display(" got : %03b %03b", got[5:3], got[2:0]);
|
|
$display(" want: %03b %03b", want[5:3], want[2:0]);
|
|
dynamicAssert(got == want, "wrong arbiter output");
|
|
endrule
|
|
|
|
(* no_implicit_conditions, fire_when_enabled *)
|
|
rule advance_test;
|
|
let next = idx+1;
|
|
let max = fromInteger(arrayLength(vectorToArray(tests)));
|
|
if (next == max) begin
|
|
$display("OK TestMemoryArbiter");
|
|
$finish;
|
|
end
|
|
else
|
|
idx <= next;
|
|
endrule
|
|
|
|
// function Stmt testMemoryArbiter();
|
|
// return seq
|
|
// testCase(idle, idle, idle, idle, idle, idle,
|
|
// grant(-1, -1));
|
|
//
|
|
// // Simple single-client accesses
|
|
// testCase(readA(1), idle, idle, idle, idle, idle,
|
|
// grant(0, -1));
|
|
// testCase(writeA(1), idle, idle, idle, idle, idle,
|
|
// grant(0, -1));
|
|
// testCase(idle, readA(1), idle, idle, idle, idle,
|
|
// grant(1, -1));
|
|
// testCase(idle, writeA(1), idle, idle, idle, idle,
|
|
// grant(1, -1));
|
|
// testCase(idle, idle, read(1), idle, idle, idle,
|
|
// grant(2, -1));
|
|
// testCase(idle, idle, idle, read(1), idle, idle,
|
|
// grant(-1, 0));
|
|
// testCase(idle, idle, idle, idle, read(1), idle,
|
|
// grant(-1, 1));
|
|
// testCase(idle, idle, idle, idle, idle, read(1),
|
|
// grant(-1, 2));
|
|
// endseq;
|
|
// endfunction
|
|
endmodule
|
|
|
|
endpackage
|