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 module mkConstantValue(Integer cnst, Get#(Bit#(8)) ifc); method ActionValue#(Bit#(8)) get(); return fromInteger(cnst); endmethod endmodule module mkIncrementingValue(Get#(Bit#(8))); Reg#(Bit#(8)) val <- mkReg(0); 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 module mkSlowReader(Get#(Bit#(8)) inner, Get#(Bit#(8)) ifc); Reg#(Bool) delay <- mkReg(True); (* 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 endmodule module mkWriter(Server#(VRAMRequest, VRAMResponse) dut, Get#(Bit#(8)) 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.get(); 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, Get#(Bit#(8)) 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.get(); if (flags.verbose) $display("%0d: verify_read(%0d) = %0d, want %0d", cycles.all, verify_idx, got, want); dynamicAssert(got.data == want, "wrong value seen during read"); 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 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 (* 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); let slow_reader <- mkSlowConsumerTest(dut); runTest(100000, mkTest("VRAMCore", seq //mkTest("VRAMCore/simple", simple); //mkTest("VRAMCore/two_port", two_port); mkTest("VRAMCore/slow_reader", slow_reader); endseq)); endmodule endpackage