From f7e3f36254961b4649af095b1c129671ee0911d8 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 14 Sep 2024 16:40:14 -0700 Subject: [PATCH] vram/VRAM: add tests for the arbitration glue and the entire VRAM stack --- vram/VRAM.bsv | 2 + vram/VRAM_Test.bsv | 136 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 vram/VRAM_Test.bsv diff --git a/vram/VRAM.bsv b/vram/VRAM.bsv index 09198d0..407bcd4 100644 --- a/vram/VRAM.bsv +++ b/vram/VRAM.bsv @@ -16,6 +16,8 @@ export VRAMAddr, VRAMData, VRAMRequest(..), VRAMResponse(..); export VRAMServer(..); export VRAM(..), mkVRAM; +export mkArbitratedVRAMServers; + // A VRAMServer is a memory port. typedef Server#(VRAMRequest, VRAMResponse) VRAMServer; diff --git a/vram/VRAM_Test.bsv b/vram/VRAM_Test.bsv new file mode 100644 index 0000000..5164d86 --- /dev/null +++ b/vram/VRAM_Test.bsv @@ -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