vram/VRAM: add tests for the arbitration glue and the entire VRAM stack
This commit is contained in:
parent
8247661a38
commit
f7e3f36254
|
@ -16,6 +16,8 @@ export VRAMAddr, VRAMData, VRAMRequest(..), VRAMResponse(..);
|
||||||
export VRAMServer(..);
|
export VRAMServer(..);
|
||||||
export VRAM(..), mkVRAM;
|
export VRAM(..), mkVRAM;
|
||||||
|
|
||||||
|
export mkArbitratedVRAMServers;
|
||||||
|
|
||||||
// A VRAMServer is a memory port.
|
// A VRAMServer is a memory port.
|
||||||
typedef Server#(VRAMRequest, VRAMResponse) VRAMServer;
|
typedef Server#(VRAMRequest, VRAMResponse) VRAMServer;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
package VRAM_Test;
|
||||||
|
|
||||||
|
import Assert::*;
|
||||||
|
import StmtFSM::*;
|
||||||
|
import GetPut::*;
|
||||||
|
import ClientServer::*;
|
||||||
|
import Connectable::*;
|
||||||
|
import Vector::*;
|
||||||
|
|
||||||
|
import MemArbiter::*;
|
||||||
|
import Testing::*;
|
||||||
|
import VRAM::*;
|
||||||
|
|
||||||
|
interface FakeVRAM;
|
||||||
|
interface VRAMServer server;
|
||||||
|
method Action next_response(VRAMResponse resp);
|
||||||
|
method Maybe#(VRAMRequest) last_request();
|
||||||
|
endinterface
|
||||||
|
|
||||||
|
module mkFakeVRAM(FakeVRAM);
|
||||||
|
Reg#(Maybe#(VRAMRequest)) req <- mkReg(tagged Invalid);
|
||||||
|
Reg#(Maybe#(VRAMResponse)) resp <- mkReg(tagged Invalid);
|
||||||
|
|
||||||
|
interface VRAMServer server;
|
||||||
|
interface Put request;
|
||||||
|
method Action put(r);
|
||||||
|
req <= tagged Valid r;
|
||||||
|
endmethod
|
||||||
|
endinterface
|
||||||
|
interface Get response;
|
||||||
|
method ActionValue#(VRAMResponse) get() if (resp matches tagged Valid .respval &&& req matches tagged Valid .reqval &&& reqval.data matches tagged Invalid);
|
||||||
|
resp <= tagged Invalid;
|
||||||
|
return respval;
|
||||||
|
endmethod
|
||||||
|
endinterface
|
||||||
|
endinterface
|
||||||
|
method Action next_response(r) if (resp matches tagged Invalid);
|
||||||
|
resp <= tagged Valid r;
|
||||||
|
endmethod
|
||||||
|
method Maybe#(VRAMRequest) last_request();
|
||||||
|
return req;
|
||||||
|
endmethod
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module mkArbitratedVRAMServersTest(FSM);
|
||||||
|
let testflags <- mkTestFlags();
|
||||||
|
let cycles <- mkCycleCounter();
|
||||||
|
|
||||||
|
let vram <- mkFakeVRAM();
|
||||||
|
MemArbiter#(3, VRAMAddr) arb <- mkPriorityMemArbiter();
|
||||||
|
|
||||||
|
Vector#(3, VRAMServer) ports <- mkArbitratedVRAMServers(vram.server, arb);
|
||||||
|
|
||||||
|
function Action check_read(VRAMServer port, VRAMAddr want_addr, VRAMData want_data);
|
||||||
|
return action
|
||||||
|
let want_request = VRAMRequest{addr: want_addr, data: tagged Invalid};
|
||||||
|
if (testflags.verbose)
|
||||||
|
$display("Last received VRAM request: ", fshow(vram.last_request), " want ", fshow(want_request));
|
||||||
|
dynamicAssert(vram.last_request == tagged Valid want_request, "wrong request seen by vram for read");
|
||||||
|
|
||||||
|
let got <- port.response.get();
|
||||||
|
if (testflags.verbose)
|
||||||
|
$display("VRAM.read() = %0d, want %0d", got.data, want_data);
|
||||||
|
dynamicAssert(got.data == want_data, "wrong data seen in vram read");
|
||||||
|
endaction;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function Action check_write(VRAMAddr want_addr, VRAMData data);
|
||||||
|
return action
|
||||||
|
let want = VRAMRequest{addr: want_addr, data: tagged Valid data};
|
||||||
|
if (testflags.verbose)
|
||||||
|
$display("Last received VRAM request: ", fshow(vram.last_request), " want ", fshow(want));
|
||||||
|
dynamicAssert(vram.last_request == tagged Valid want, "wrong request seen by vram for write");
|
||||||
|
endaction;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
let fsm <- mkFSM(seq
|
||||||
|
// Single write
|
||||||
|
ports[1].request.put(VRAMRequest{addr: 123, data: tagged Valid 42});
|
||||||
|
check_write(123, 42);
|
||||||
|
|
||||||
|
// Single read
|
||||||
|
vram.next_response(VRAMResponse{data: 23});
|
||||||
|
ports[1].request.put(VRAMRequest{addr: 124, data: tagged Invalid});
|
||||||
|
check_read(ports[1], 124, 23);
|
||||||
|
|
||||||
|
// Concurrent ops, process port 1 response first to check
|
||||||
|
// buffering allows port 0 op to finish and port 1 to proceed
|
||||||
|
vram.next_response(VRAMResponse{data: 11});
|
||||||
|
par
|
||||||
|
vram.next_response(VRAMResponse{data: 66});
|
||||||
|
ports[0].request.put(VRAMRequest{addr: 123, data: tagged Invalid});
|
||||||
|
ports[1].request.put(VRAMRequest{addr: 125, data: tagged Invalid});
|
||||||
|
endpar
|
||||||
|
check_read(ports[1], 125, 66);
|
||||||
|
check_read(ports[0], 125, 11); // note, 125 because the last op is still port 1's read
|
||||||
|
endseq);
|
||||||
|
return fsm;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module mkTestFull(FSM);
|
||||||
|
let testflags <- mkTestFlags();
|
||||||
|
|
||||||
|
let dut <- mkVRAM(4);
|
||||||
|
|
||||||
|
let fsm <- mkFSM(seq
|
||||||
|
dut.cpu.request.put(VRAMRequest{addr: 1, data: tagged Valid 42});
|
||||||
|
dut.cpu.request.put(VRAMRequest{addr: 1, data: tagged Invalid});
|
||||||
|
action
|
||||||
|
let resp <- dut.cpu.response.get();
|
||||||
|
if (testflags.verbose)
|
||||||
|
$display("vram read: ", fshow(resp));
|
||||||
|
dynamicAssert(resp.data == 42, "wrong data read after writing");
|
||||||
|
endaction
|
||||||
|
endseq);
|
||||||
|
return fsm;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module mkTB();
|
||||||
|
let testGlue <- mkArbitratedVRAMServersTest();
|
||||||
|
let testFull <- mkTestFull();
|
||||||
|
|
||||||
|
runTest(100,
|
||||||
|
mkTest("VRAM", seq
|
||||||
|
mkTest("VRAM/Glue", seq
|
||||||
|
testGlue.start();
|
||||||
|
await(testGlue.done);
|
||||||
|
endseq);
|
||||||
|
mkTest("VRAM/Full", seq
|
||||||
|
testFull.start();
|
||||||
|
await(testFull.done);
|
||||||
|
endseq);
|
||||||
|
endseq));
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
endpackage
|
Loading…
Reference in New Issue