Compare commits

...

2 Commits

Author SHA1 Message Date
David Anderson 4b6b34e131 vram/VRAMCore: add tests, fix bug found by same 2024-09-09 11:16:21 -07:00
David Anderson ffb9f7c062 lib/Testing: add helper module to access test flags
Notably, this lets me plumb +v for verbose test output.
2024-09-09 11:15:51 -07:00
3 changed files with 213 additions and 2 deletions

View File

@ -36,6 +36,21 @@ module mkCycleCounter(CycleCounter);
method all = total._read; method all = total._read;
endmodule endmodule
interface TestFlags;
method Bool verbose();
endinterface
module mkTestFlags(TestFlags);
Wire#(Bool) verbose_val <- mkBypassWire();
rule every;
let v <- $test$plusargs("v");
verbose_val <= v;
endrule
method verbose = verbose_val;
endmodule
// mkTest runs the given test, printing status text before and after // mkTest runs the given test, printing status text before and after
// the run. Tests can be nested. // the run. Tests can be nested.
function Stmt mkTest(String name, Stmt test); function Stmt mkTest(String name, Stmt test);

View File

@ -120,7 +120,7 @@ module mkByteRAMArray(Integer num_chips, ByteRAM ifc);
method Action put(ChipAddr chip_select, Bool write, ByteAddr addr, VRAMData data_in); method Action put(ChipAddr chip_select, Bool write, ByteAddr addr, VRAMData data_in);
for (Integer i=0; i<num_chips; i=i+1) for (Integer i=0; i<num_chips; i=i+1)
blocks[i].portA.put(chip_select, write, addr, data_in); blocks[i].portA.put(chip_select, write, addr, data_in);
if (write) if (!write)
read_chip_A <= chip_select; read_chip_A <= chip_select;
endmethod endmethod
method VRAMData read(); method VRAMData read();
@ -138,7 +138,7 @@ module mkByteRAMArray(Integer num_chips, ByteRAM ifc);
method Action put(ChipAddr chip_select, Bool write, ByteAddr addr, VRAMData data_in); method Action put(ChipAddr chip_select, Bool write, ByteAddr addr, VRAMData data_in);
for (Integer i=0; i<num_chips; i=i+1) for (Integer i=0; i<num_chips; i=i+1)
blocks[i].portB.put(chip_select, write, addr, data_in); blocks[i].portB.put(chip_select, write, addr, data_in);
if (write) if (!write)
read_chip_B <= chip_select; read_chip_B <= chip_select;
endmethod endmethod
method VRAMData read(); method VRAMData read();

196
vram/VRAMCore_Test.bsv Normal file
View File

@ -0,0 +1,196 @@
package VRAMCore_Test;
import Assert::*;
import GetPut::*;
import ClientServer::*;
import Testing::*;
import StmtFSM::*;
import VRAMCore::*;
import Testing::*;
interface Machine;
method Action start(VRAMAddr start, VRAMAddr count);
method Bool done();
endinterface
function ActionValue#(Bool) verbose();
return (actionvalue
let ret <- $test$plusargs("v");
return ret;
endactionvalue);
endfunction
typedef (function ActionValue#(Bit#(8)) next()) ValFn;
function ValFn constant_value(Integer cnst);
function ActionValue#(Bit#(8)) next();
return (actionvalue
return fromInteger(cnst);
endactionvalue);
endfunction
return next;
endfunction
module mkIncrementingValue(ValFn);
Reg#(Bit#(8)) val <- mkReg(0);
function ActionValue#(Bit#(8)) next();
return (actionvalue
val <= val+1;
return val;
endactionvalue);
endfunction
return next;
endmodule
module mkWriter(Server#(VRAMRequest, VRAMResponse) dut, ValFn next_value, Machine ifc);
let flags <- mkTestFlags();
let cycles <- mkCycleCounter();
let write_cycle_time <- mkCycleCounter();
Reg#(VRAMAddr) total <- mkReg(0);
Reg#(VRAMAddr) remaining <- mkReg(0);
Reg#(VRAMAddr) idx <- mkReg(0);
rule write (remaining > 0);
dynamicAssert(write_cycle_time == 1, "write didn't happen every cycle");
write_cycle_time.reset();
let data <- next_value();
let req = VRAMRequest{
addr: idx,
data: tagged Valid data
};
dut.request.put(req);
if (flags.verbose)
$display("%0d: write(%0d, %0d)", cycles.all, idx, data);
if (remaining == 1)
$display("Wrote %0d values in %0d cycles", total, cycles);
remaining <= remaining-1;
idx <= idx+1;
endrule
method Action start(VRAMAddr start_addr, VRAMAddr count) if (remaining == 0);
cycles.reset();
write_cycle_time.reset();
total <= count;
remaining <= count;
idx <= start_addr;
endmethod
method Bool done();
return remaining == 0;
endmethod
endmodule
module mkReader(Server#(VRAMRequest, VRAMResponse) dut, ValFn next_value, Machine ifc);
let flags <- mkTestFlags();
let cycles <- mkCycleCounter();
Reg#(VRAMAddr) total <- mkReg(0);
Reg#(VRAMAddr) issue_remaining <- mkReg(0);
Reg#(VRAMAddr) issue_idx <- mkReg(0);
Reg#(VRAMAddr) verify_remaining <- mkReg(0);
Reg#(VRAMAddr) verify_idx <- mkReg(0);
rule issue_read (issue_remaining > 0);
let req = VRAMRequest{
addr: issue_idx,
data: tagged Invalid
};
dut.request.put(req);
if (flags.verbose)
$display("%0d: issue_read(%0d)", cycles.all, issue_idx);
if (issue_remaining == 1)
$display("Issued %0d reads in %0d cycles", total, cycles);
issue_remaining <= issue_remaining-1;
issue_idx <= issue_idx+1;
endrule
rule verify_read (verify_remaining > 0);
let got <- dut.response.get();
let want <- next_value();
dynamicAssert(got.data == want, "wrong value seen during read");
if (flags.verbose)
$display("%0d: verify_read(%0d) = %0d, want %0d", cycles.all, verify_idx, got, want);
if (verify_remaining == 1)
$display("Verified %0d reads in %0d cycles", total, cycles);
verify_remaining <= verify_remaining-1;
verify_idx <= verify_idx+1;
endrule
method Action start(VRAMAddr start_addr, VRAMAddr count) if (issue_remaining == 0 && verify_remaining == 0);
cycles.reset();
total <= count;
issue_remaining <= count;
verify_remaining <= count;
issue_idx <= start_addr;
verify_idx <= start_addr;
endmethod
method Bool done();
return issue_remaining == 0 && verify_remaining == 0;
endmethod
endmodule
(* descending_urgency="writer.write,reader.issue_read" *)
module mkSimpleTest(VRAMCore dut, Stmt ret);
let winc <- mkIncrementingValue();
let writer <- mkWriter(dut.portA, winc);
let rinc <- mkIncrementingValue();
let reader <- mkReader(dut.portA, rinc);
return (seq
writer.start(3000, 6000);
await(writer.done);
reader.start(3000, 6000);
await(reader.done);
endseq);
endmodule
module mkTwoPortTest(VRAMCore dut, Stmt ret);
let winc <- mkIncrementingValue();
let writer <- mkWriter(dut.portA, winc);
let rinc <- mkIncrementingValue();
let reader <- mkReader(dut.portB, rinc);
return (seq
writer.start(0, 1000);
// Delay a little before starting the reader, so it's
// trailing the writer by a few addrs.
repeat (2) noAction;
reader.start(0, 1000);
await(writer.done);
await(reader.done);
endseq);
endmodule
(* descending_urgency="simple.reader.issue_read,two_port.writer.write" *)
module mkTB(Empty);
let dut <- mkVRAMCore(112);
let simple <- mkSimpleTest(dut);
let two_port <- mkTwoPortTest(dut);
runTest(100000,
mkTest("VRAMCore", seq
mkTest("VRAMCore/simple", simple);
mkTest("VRAMCore/two_port", two_port);
endseq));
endmodule
endpackage