2024-09-09 20:15:43 +02:00
|
|
|
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
|
|
|
|
|
2024-09-19 06:31:34 +02:00
|
|
|
module mkConstantValue(Integer cnst, Get#(Bit#(8)) ifc);
|
|
|
|
method ActionValue#(Bit#(8)) get();
|
|
|
|
return fromInteger(cnst);
|
|
|
|
endmethod
|
|
|
|
endmodule
|
2024-09-09 20:15:43 +02:00
|
|
|
|
2024-09-19 06:31:34 +02:00
|
|
|
module mkIncrementingValue(Get#(Bit#(8)));
|
|
|
|
Reg#(Bit#(8)) val <- mkReg(0);
|
2024-09-09 20:15:43 +02:00
|
|
|
|
2024-09-19 06:31:34 +02:00
|
|
|
method ActionValue#(Bit#(8)) get();
|
|
|
|
// Cycle through 101 values. 101 is prime, so the pattern it
|
|
|
|
// generates doesn't align to a power of two and should detect
|
|
|
|
// any memory mapping errors.
|
|
|
|
if (val == 100)
|
|
|
|
val <= 0;
|
|
|
|
else
|
|
|
|
val <= val+1;
|
|
|
|
|
|
|
|
// Add another number to get all nonzero values, to detect
|
|
|
|
// writes that don't stick.
|
|
|
|
return 23+val;
|
|
|
|
endmethod
|
|
|
|
endmodule
|
2024-09-09 20:15:43 +02:00
|
|
|
|
2024-09-19 06:31:34 +02:00
|
|
|
module mkSlowReader(Get#(Bit#(8)) inner, Get#(Bit#(8)) ifc);
|
|
|
|
Reg#(Bool) delay <- mkReg(True);
|
2024-09-09 20:15:43 +02:00
|
|
|
|
2024-09-19 06:31:34 +02:00
|
|
|
(* no_implicit_conditions,fire_when_enabled *)
|
|
|
|
rule clear_delay (delay);
|
|
|
|
delay <= False;
|
|
|
|
endrule
|
|
|
|
|
|
|
|
method ActionValue#(Bit#(8)) get() if (!delay);
|
|
|
|
delay <= True;
|
|
|
|
let ret <- inner.get();
|
|
|
|
return ret;
|
|
|
|
endmethod
|
2024-09-09 20:15:43 +02:00
|
|
|
endmodule
|
|
|
|
|
2024-09-19 06:31:34 +02:00
|
|
|
module mkWriter(Server#(VRAMRequest, VRAMResponse) dut, Get#(Bit#(8)) next_value, Machine ifc);
|
2024-09-09 20:15:43 +02:00
|
|
|
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();
|
|
|
|
|
2024-09-19 06:31:34 +02:00
|
|
|
let data <- next_value.get();
|
2024-09-09 20:15:43 +02:00
|
|
|
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
|
|
|
|
|
2024-09-19 06:31:34 +02:00
|
|
|
module mkReader(Server#(VRAMRequest, VRAMResponse) dut, Get#(Bit#(8)) next_value, Machine ifc);
|
2024-09-09 20:15:43 +02:00
|
|
|
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();
|
2024-09-19 06:31:34 +02:00
|
|
|
let want <- next_value.get();
|
2024-09-09 20:15:43 +02:00
|
|
|
|
|
|
|
if (flags.verbose)
|
|
|
|
$display("%0d: verify_read(%0d) = %0d, want %0d", cycles.all, verify_idx, got, want);
|
2024-09-19 06:31:34 +02:00
|
|
|
dynamicAssert(got.data == want, "wrong value seen during read");
|
2024-09-09 20:15:43 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2024-09-19 06:31:34 +02:00
|
|
|
module mkSlowConsumerTest(VRAMCore dut, Stmt ret);
|
|
|
|
let winc <- mkIncrementingValue();
|
|
|
|
let writer <- mkWriter(dut.portA, winc);
|
|
|
|
|
|
|
|
let rinc <- mkIncrementingValue();
|
|
|
|
let rinc_slow <- mkSlowReader(rinc);
|
|
|
|
let reader <- mkReader(dut.portA, rinc_slow);
|
|
|
|
|
|
|
|
return (seq
|
|
|
|
writer.start(3000, 6000);
|
|
|
|
await(writer.done);
|
|
|
|
|
|
|
|
reader.start(3000, 6000);
|
|
|
|
await(reader.done);
|
|
|
|
endseq);
|
|
|
|
endmodule
|
|
|
|
|
2024-09-09 20:15:43 +02:00
|
|
|
(* 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);
|
2024-09-19 06:31:34 +02:00
|
|
|
let slow_reader <- mkSlowConsumerTest(dut);
|
2024-09-09 20:15:43 +02:00
|
|
|
|
|
|
|
runTest(100000,
|
|
|
|
mkTest("VRAMCore", seq
|
2024-09-19 06:31:34 +02:00
|
|
|
//mkTest("VRAMCore/simple", simple);
|
|
|
|
//mkTest("VRAMCore/two_port", two_port);
|
|
|
|
mkTest("VRAMCore/slow_reader", slow_reader);
|
2024-09-09 20:15:43 +02:00
|
|
|
endseq));
|
|
|
|
endmodule
|
|
|
|
|
|
|
|
endpackage
|