提交 4a28083f 编写于 作者: Y Yinan Xu

Merge remote-tracking branch 'origin/master' into debian-gogogo

...@@ -90,6 +90,12 @@ VEXTRA_FLAGS += --savable ...@@ -90,6 +90,12 @@ VEXTRA_FLAGS += --savable
EMU_CXXFLAGS += -DVM_SAVABLE EMU_CXXFLAGS += -DVM_SAVABLE
endif endif
# Verilator coverage
EMU_COVERAGE ?=
ifeq ($(EMU_COVERAGE),1)
VEXTRA_FLAGS += --coverage-line --coverage-toggle
endif
# co-simulation with DRAMsim3 # co-simulation with DRAMsim3
ifeq ($(WITH_DRAMSIM3),1) ifeq ($(WITH_DRAMSIM3),1)
EMU_CXXFLAGS += -I$(DRAMSIM3_HOME)/src EMU_CXXFLAGS += -I$(DRAMSIM3_HOME)/src
...@@ -167,6 +173,11 @@ emu: $(EMU) ...@@ -167,6 +173,11 @@ emu: $(EMU)
ls build ls build
$(EMU) -i $(IMAGE) $(EMU_FLAGS) $(EMU) -i $(IMAGE) $(EMU_FLAGS)
coverage:
verilator_coverage --annotate build/logs/annotated --annotate-min 1 build/logs/coverage.dat
python3 scripts/coverage/coverage.py build/logs/annotated/XSSimTop.v build/XSSimTop_annotated.v
python3 scripts/coverage/statistics.py build/XSSimTop_annotated.v >build/coverage.log
# extract verilog module from sim_top.v # extract verilog module from sim_top.v
# usage: make vme VME_MODULE=Roq # usage: make vme VME_MODULE=Roq
vme: $(SIM_TOP_V) vme: $(SIM_TOP_V)
......
...@@ -3,26 +3,223 @@ ...@@ -3,26 +3,223 @@
import sys import sys
import re import re
import copy import copy
import pprint
COVERRED = "COVERRED"
NOT_COVERRED = "NOT_COVERRED"
DONTCARE = "DONTCARE"
BEGIN = "BEGIN"
END = "END"
CHILDREN = "CHILDREN"
MODULE = "MODULE"
INSTANCE = "INSTANCE"
TYPE="TYPE"
ROOT="ROOT"
NODE="NODE"
SELFCOVERAGE="SELFCOVERAGE"
TREECOVERAGE="TREECOVERAGE"
def get_lines(input_file):
lines = []
with open(input_file) as f:
for line in f:
lines.append(line)
return lines
def get_line_annotation(lines):
line_annotations = []
# pattern_1: 040192 if(array_0_MPORT_en & array_0_MPORT_mask) begin
# pattern_2: 2218110 end else if (_T_30) begin // @[Conditional.scala 40:58]
# pattern_2: 000417 end else begin
coverred_pattern_1 = re.compile('^\s*(\d+)\s+if')
coverred_pattern_2 = re.compile('^\s*(\d+)\s+end else')
not_coverred_pattern_1 = re.compile('^\s*(%0+)\s+if')
not_coverred_pattern_2 = re.compile('^\s*(%0+)\s+end else')
for line in lines:
coverred_match = coverred_pattern_1.search(line) or coverred_pattern_2.search(line)
not_coverred_match = not_coverred_pattern_1.search(line) or not_coverred_pattern_2.search(line)
assert not (coverred_match and not_coverred_match)
if coverred_match:
line_annotations.append(COVERRED)
elif not_coverred_match:
line_annotations.append(NOT_COVERRED)
else:
line_annotations.append(DONTCARE)
return line_annotations
# get the line coverage statistics in line range [start, end)
def get_coverage_statistics(line_annotations, start, end):
coverred = 0
not_coverred = 0
for i in range(start, end):
if line_annotations[i] == COVERRED:
coverred += 1
if line_annotations[i] == NOT_COVERRED:
not_coverred += 1
# deal with divide by zero
coverage = 1.0
if coverred + not_coverred != 0:
coverage = float(coverred) / (coverred + not_coverred)
return (coverred, not_coverred, coverage)
# get modules and all it's submodules
def get_modules(lines):
modules = {}
module_pattern = re.compile("module (\w+)\(")
endmodule_pattern = re.compile("endmodule")
submodule_pattern = re.compile("(\w+) (\w+) \( // @\[\w+.scala \d+:\d+\]")
line_count = 0
name = "ModuleName"
for line in lines:
module_match = module_pattern.search(line)
endmodule_match = endmodule_pattern.search(line)
submodule_match = submodule_pattern.search(line)
assert not (module_match and endmodule_match)
if module_match:
name = module_match.group(1)
# print("module_match: module: %s" % name)
assert name not in modules
# [begin
modules[name] = {}
modules[name][BEGIN] = line_count
# the first time we see a module, we treat as a root node
modules[name][TYPE] = ROOT
if endmodule_match:
# print("endmodule_match: module: %s" % name)
assert name in modules
assert END not in modules[name]
# end)
modules[name][END] = line_count + 1
# reset module name to invalid
name = "ModuleName"
if submodule_match:
# submodule must be inside hierarchy
assert name != "ModuleName"
submodule_type = submodule_match.group(1)
submodule_instance = submodule_match.group(2)
# print("submodule_match: type: %s instance: %s" % (submodule_type, submodule_instance))
# submodules should be defined first
# if we can not find it's definition
# we consider it a black block module
if submodule_type not in modules:
print("Module %s is a Blackbox" % submodule_type)
else:
# mark submodule as a tree node
# it's no longer root any more
modules[submodule_type][TYPE] = NODE
if CHILDREN not in modules[name]:
modules[name][CHILDREN] = []
submodule = {MODULE: submodule_type, INSTANCE: submodule_instance}
modules[name][CHILDREN].append(submodule)
line_count += 1
return modules
# we define two coverage metrics:
# self coverage: coverage results of this module(excluding submodules)
# tree coverage: coverage results of this module(including submodules)
def get_tree_coverage(modules, coverage):
def dfs(module):
if TREECOVERAGE not in modules[module]:
self_coverage = modules[module][SELFCOVERAGE]
if CHILDREN not in modules[module]:
modules[module][TREECOVERAGE] = self_coverage
else:
coverred = self_coverage[0]
not_coverred = self_coverage[1]
# the dfs part
for child in modules[module][CHILDREN]:
child_coverage = dfs(child[MODULE])
coverred += child_coverage[0]
not_coverred += child_coverage[1]
# deal with divide by zero
coverage = 1.0
if coverred + not_coverred != 0:
coverage = float(coverred) / (coverred + not_coverred)
modules[module][TREECOVERAGE] = (coverred, not_coverred, coverage)
return modules[module][TREECOVERAGE]
for module in modules:
modules[module][SELFCOVERAGE] = coverage[module]
for module in modules:
modules[module][TREECOVERAGE] = dfs(module)
return modules
# arg1: tree coverage results
# arg2: coverage type
def sort_coverage(coverage, coverage_type):
l = [(module, coverage[module][coverage_type])for module in coverage]
l.sort(key=lambda x:x[1][2])
return l
def print_tree_coverage(tree_coverage):
def dfs(module, level):
# print current node
tree = tree_coverage[module][TREECOVERAGE]
self = tree_coverage[module][SELFCOVERAGE]
print(" " * level + "- " + module)
print(" " * level + " tree", end="")
print("(%d, %d, %.2f)" % (tree[0], tree[1], tree[2] * 100.0))
print(" " * level + " self", end="")
print("(%d, %d, %.2f)" % (self[0], self[1], self[2] * 100.0))
# print children nodes
if CHILDREN in modules[module]:
# the dfs part
for child in modules[module][CHILDREN]:
dfs(child[MODULE], level + 1)
for module in tree_coverage:
if tree_coverage[module][TYPE] == ROOT:
dfs(module, 0)
if __name__ == "__main__": if __name__ == "__main__":
assert len(sys.argv) == 2, "Expect input_file" assert len(sys.argv) == 2, "Expect input_file"
input_file = sys.argv[1] input_file = sys.argv[1]
coverred = 0 pp = pprint.PrettyPrinter(indent=4)
not_coverred = 0
with open(input_file) as f: lines = get_lines(input_file)
for line in f: # print("lines:")
coverred_pattern = re.compile('^\s*(\d+)\s+if') # pp.pprint(lines)
not_coverred_pattern = re.compile('^\s*(%0+)\s+if')
annotations = get_line_annotation(lines)
# print("annotations:")
# pp.pprint(annotations)
modules = get_modules(lines)
# print("modules:")
# pp.pprint(modules)
self_coverage = {module: get_coverage_statistics(annotations, modules[module][BEGIN], modules[module][END])
for module in modules}
# print("self_coverage:")
# pp.pprint(self_coverage)
tree_coverage = get_tree_coverage(modules, self_coverage)
# print("tree_coverage:")
# pp.pprint(tree_coverage)
coverred_match = coverred_pattern.search(line) print("SelfCoverage:")
not_coverred_match = not_coverred_pattern.search(line) pp.pprint(sort_coverage(tree_coverage, SELFCOVERAGE))
assert not (coverred_match and not_coverred_match) print("TreeCoverage:")
pp.pprint(sort_coverage(tree_coverage, TREECOVERAGE))
if coverred_match:
coverred += 1
if not_coverred_match: print("AllCoverage:")
not_coverred += 1 print_tree_coverage(tree_coverage)
print("cover: %d not_cover: %d coverage: %f" %
(coverred, not_coverred, float(coverred) / (coverred + not_coverred)))
...@@ -4,7 +4,7 @@ import chisel3._ ...@@ -4,7 +4,7 @@ import chisel3._
import chisel3.util._ import chisel3.util._
object ParallelOperation { object ParallelOperation {
def apply[T <: Data](xs: Seq[T], func: (T, T) => T): T = { def apply[T](xs: Seq[T], func: (T, T) => T): T = {
require(xs.nonEmpty) require(xs.nonEmpty)
xs match { xs match {
case Seq(a) => a case Seq(a) => a
...@@ -21,12 +21,22 @@ object ParallelOR { ...@@ -21,12 +21,22 @@ object ParallelOR {
} }
} }
object ParallelORR {
def apply(in: Seq[Bool]): Bool = ParallelOR(in)
def apply(in: Bits): Bool = apply(in.asBools)
}
object ParallelAND { object ParallelAND {
def apply[T <: Data](xs: Seq[T]): T = { def apply[T <: Data](xs: Seq[T]): T = {
ParallelOperation(xs, (a: T, b:T) => (a.asUInt() & b.asUInt()).asTypeOf(xs.head)) ParallelOperation(xs, (a: T, b:T) => (a.asUInt() & b.asUInt()).asTypeOf(xs.head))
} }
} }
object ParallelANDR {
def apply(in: Seq[Bool]): Bool = ParallelAND(in)
def apply(in: Bits): Bool = apply(in.asBools)
}
object ParallelMux { object ParallelMux {
def apply[T<:Data](in: Seq[(Bool, T)]): T = { def apply[T<:Data](in: Seq[(Bool, T)]): T = {
val xs = in map { case (cond, x) => (Fill(x.getWidth, cond) & x.asUInt()).asTypeOf(in.head._2) } val xs = in map { case (cond, x) => (Fill(x.getWidth, cond) & x.asUInt()).asTypeOf(in.head._2) }
...@@ -50,4 +60,17 @@ object ParallelMin { ...@@ -50,4 +60,17 @@ object ParallelMin {
def apply[T <: Data](xs: Seq[T]): T = { def apply[T <: Data](xs: Seq[T]): T = {
ParallelOperation(xs, (a: T, b:T) => Mux(a.asUInt() < b.asUInt(),a, b).asTypeOf(xs.head)) ParallelOperation(xs, (a: T, b:T) => Mux(a.asUInt() < b.asUInt(),a, b).asTypeOf(xs.head))
} }
} }
\ No newline at end of file
object ParallelPriorityMux {
def apply[T <: Data](in: Seq[(Bool, T)]): T = {
ParallelOperation(in, (a: (Bool, T), b: (Bool, T)) => (a._1 || b._1, Mux(a._1, a._2, b._2)))._2
}
def apply[T <: Data](sel: Bits, in: Seq[T]): T = apply((0 until in.size).map(sel(_)), in)
def apply[T <: Data](sel: Seq[Bool], in: Seq[T]): T = apply(sel zip in)
}
object ParallelPriorityEncoder {
def apply(in: Seq[Bool]): UInt = ParallelPriorityMux(in, (0 until in.size).map(_.asUInt))
def apply(in: Bits): UInt = apply(in.asBools)
}
package utils
import chisel3._
import chisel3.util._
// this could be used to handle the situation
// in which we have mux sources at multiple
// locations, and this is same to multiple
// when clauses as below, but collect them
// and put them into a ParallelPrioriyMux
// when (sel1) { x := in1 }
// when (sel2) { x := in2 }
class PriorityMuxGenerator[T <: Data] {
var src: List[(Bool, T)] = List()
def register(sel: Bool, in: T) = src = (sel, in) :: src
def register(in: Seq[(Bool, T)]) = src = in.toList ::: src
def register(sel: Seq[Bool], in: Seq[T]) = src = (sel zip in).toList ::: src
def apply(): T = ParallelPriorityMux(src)
}
\ No newline at end of file
...@@ -90,7 +90,7 @@ class BranchPrediction extends XSBundle with HasIFUConst { ...@@ -90,7 +90,7 @@ class BranchPrediction extends XSBundle with HasIFUConst {
def lastHalfRVIClearMask = ~lastHalfRVIMask def lastHalfRVIClearMask = ~lastHalfRVIMask
// is taken from half RVI // is taken from half RVI
def lastHalfRVITaken = (takens & lastHalfRVIMask).orR def lastHalfRVITaken = ParallelORR(takens & lastHalfRVIMask)
def lastHalfRVIIdx = Mux(firstBankHasHalfRVI, (bankWidth-1).U, (PredictWidth-1).U) def lastHalfRVIIdx = Mux(firstBankHasHalfRVI, (bankWidth-1).U, (PredictWidth-1).U)
// should not be used if not lastHalfRVITaken // should not be used if not lastHalfRVITaken
...@@ -102,18 +102,18 @@ class BranchPrediction extends XSBundle with HasIFUConst { ...@@ -102,18 +102,18 @@ class BranchPrediction extends XSBundle with HasIFUConst {
def brNotTakens = ~realTakens & realBrMask def brNotTakens = ~realTakens & realBrMask
def sawNotTakenBr = VecInit((0 until PredictWidth).map(i => def sawNotTakenBr = VecInit((0 until PredictWidth).map(i =>
(if (i == 0) false.B else brNotTakens(i-1,0).orR))) (if (i == 0) false.B else ParallelORR(brNotTakens(i-1,0)))))
// def hasNotTakenBrs = (brNotTakens & LowerMaskFromLowest(realTakens)).orR // def hasNotTakenBrs = (brNotTakens & LowerMaskFromLowest(realTakens)).orR
def unmaskedJmpIdx = PriorityEncoder(takens) def unmaskedJmpIdx = ParallelPriorityEncoder(takens)
def saveHalfRVI = (firstBankHasHalfRVI && (unmaskedJmpIdx === (bankWidth-1).U || !(takens.orR))) || def saveHalfRVI = (firstBankHasHalfRVI && (unmaskedJmpIdx === (bankWidth-1).U || !(ParallelORR(takens)))) ||
(lastBankHasHalfRVI && unmaskedJmpIdx === (PredictWidth-1).U) (lastBankHasHalfRVI && unmaskedJmpIdx === (PredictWidth-1).U)
// could get PredictWidth-1 when only the first bank is valid // could get PredictWidth-1 when only the first bank is valid
def jmpIdx = PriorityEncoder(realTakens) def jmpIdx = ParallelPriorityEncoder(realTakens)
// only used when taken // only used when taken
def target = targets(jmpIdx) def target = ParallelPriorityMux(realTakens, targets)
def taken = realTakens.orR def taken = ParallelORR(realTakens)
def takenOnBr = taken && realBrMask(jmpIdx) def takenOnBr = taken && ParallelPriorityMux(realTakens, realBrMask.asBools)
def hasNotTakenBrs = Mux(taken, sawNotTakenBr(jmpIdx), brNotTakens.orR) def hasNotTakenBrs = Mux(taken, ParallelPriorityMux(realTakens, sawNotTakenBr), ParallelORR(brNotTakens))
} }
class BranchInfo extends XSBundle with HasBPUParameter { class BranchInfo extends XSBundle with HasBPUParameter {
......
...@@ -140,23 +140,15 @@ class IFU extends XSModule with HasIFUConst ...@@ -140,23 +140,15 @@ class IFU extends XSModule with HasIFUConst
.elsewhen (if2_flush) { if2_valid := false.B } .elsewhen (if2_flush) { if2_valid := false.B }
.elsewhen (if2_fire) { if2_valid := false.B } .elsewhen (if2_fire) { if2_valid := false.B }
when (RegNext(reset.asBool) && !reset.asBool) { val npcGen = new PriorityMuxGenerator[UInt]
if1_npc := resetVector.U(VAddrBits.W) npcGen.register(true.B, RegNext(if1_npc))
}.elsewhen (if2_fire) { npcGen.register(if2_fire, if2_snpc)
if1_npc := if2_snpc
}.otherwise {
if1_npc := RegNext(if1_npc)
}
val if2_bp = bpu.io.out(0) val if2_bp = bpu.io.out(0)
// val if2_GHInfo = wrapGHInfo(if2_bp, if2_predHist)
// if taken, bp_redirect should be true // if taken, bp_redirect should be true
// when taken on half RVI, we suppress this redirect signal // when taken on half RVI, we suppress this redirect signal
if2_redirect := if2_fire && if2_bp.taken if2_redirect := if2_fire && if2_bp.taken
when (if2_redirect) { npcGen.register(if2_redirect, if2_bp.target)
if1_npc := if2_bp.target
}
if2_predicted_gh := if2_gh.update(if2_bp.hasNotTakenBrs, if2_bp.takenOnBr) if2_predicted_gh := if2_gh.update(if2_bp.hasNotTakenBrs, if2_bp.takenOnBr)
...@@ -166,7 +158,6 @@ class IFU extends XSModule with HasIFUConst ...@@ -166,7 +158,6 @@ class IFU extends XSModule with HasIFUConst
val if3_fire = if3_valid && if4_ready && (inLoop || io.icacheResp.valid) && !if3_flush val if3_fire = if3_valid && if4_ready && (inLoop || io.icacheResp.valid) && !if3_flush
val if3_pc = RegEnable(if2_pc, if2_fire) val if3_pc = RegEnable(if2_pc, if2_fire)
val if3_predHist = RegEnable(if2_predHist, enable=if2_fire) val if3_predHist = RegEnable(if2_predHist, enable=if2_fire)
// val if3_nextValidPC = Mux(if2_valid)
if3_ready := if3_fire || !if3_valid || if3_flush if3_ready := if3_fire || !if3_valid || if3_flush
when (if3_flush) { if3_valid := false.B } when (if3_flush) { if3_valid := false.B }
.elsewhen (if2_fire) { if3_valid := true.B } .elsewhen (if2_fire) { if3_valid := true.B }
...@@ -181,7 +172,7 @@ class IFU extends XSModule with HasIFUConst ...@@ -181,7 +172,7 @@ class IFU extends XSModule with HasIFUConst
val hasPrevHalfInstrReq = prevHalfInstrReq.valid val hasPrevHalfInstrReq = prevHalfInstrReq.valid
val if3_prevHalfInstr = RegInit(0.U.asTypeOf(new PrevHalfInstr)) val if3_prevHalfInstr = RegInit(0.U.asTypeOf(new PrevHalfInstr))
// val if4_prevHalfInstr = Wire(new PrevHalfInstr)
// 32-bit instr crosses 2 pages, and the higher 16-bit triggers page fault // 32-bit instr crosses 2 pages, and the higher 16-bit triggers page fault
val crossPageIPF = WireInit(false.B) val crossPageIPF = WireInit(false.B)
...@@ -238,10 +229,11 @@ class IFU extends XSModule with HasIFUConst ...@@ -238,10 +229,11 @@ class IFU extends XSModule with HasIFUConst
// }.elsewhen (if3_ghInfoNotIdenticalRedirect) { // }.elsewhen (if3_ghInfoNotIdenticalRedirect) {
// if3_target := Mux(if3_bp.taken, if3_bp.target, snpc(if3_pc)) // if3_target := Mux(if3_bp.taken, if3_bp.target, snpc(if3_pc))
// } // }
npcGen.register(if3_redirect, if3_target)
when (if3_redirect) { // when (if3_redirect) {
if1_npc := if3_target // if1_npc := if3_target
} // }
//********************** IF4 ****************************// //********************** IF4 ****************************//
val if4_pd = RegEnable(pd.io.out, if3_fire) val if4_pd = RegEnable(pd.io.out, if3_fire)
...@@ -350,9 +342,7 @@ class IFU extends XSModule with HasIFUConst ...@@ -350,9 +342,7 @@ class IFU extends XSModule with HasIFUConst
// }.elsewhen (if4_ghInfoNotIdenticalRedirect) { // }.elsewhen (if4_ghInfoNotIdenticalRedirect) {
// if4_target := Mux(if4_bp.taken, if4_bp.target, if4_snpc) // if4_target := Mux(if4_bp.taken, if4_bp.target, if4_snpc)
// } // }
when (if4_redirect) { npcGen.register(if4_redirect, if4_target)
if1_npc := if4_target
}
when (if4_fire) { when (if4_fire) {
final_gh := if4_predicted_gh final_gh := if4_predicted_gh
...@@ -378,13 +368,11 @@ class IFU extends XSModule with HasIFUConst ...@@ -378,13 +368,11 @@ class IFU extends XSModule with HasIFUConst
flush_final_gh := true.B flush_final_gh := true.B
} }
when (loopBufPar.LBredirect.valid) { npcGen.register(loopBufPar.LBredirect.valid, loopBufPar.LBredirect.bits)
if1_npc := loopBufPar.LBredirect.bits npcGen.register(io.redirect.valid, io.redirect.bits)
} npcGen.register(RegNext(reset.asBool) && !reset.asBool, resetVector.U(VAddrBits.W))
when (io.redirect.valid) { if1_npc := npcGen()
if1_npc := io.redirect.bits
}
when(inLoop) { when(inLoop) {
io.icacheReq.valid := if4_flush io.icacheReq.valid := if4_flush
......
...@@ -247,6 +247,13 @@ uint64_t Emulator::execute(uint64_t max_cycle, uint64_t max_instr) { ...@@ -247,6 +247,13 @@ uint64_t Emulator::execute(uint64_t max_cycle, uint64_t max_instr) {
diff.wdata = wdata; diff.wdata = wdata;
diff.wdst = wdst; diff.wdst = wdst;
#if VM_COVERAGE == 1
// we dump coverage into files at the end
// since we are not sure when an emu will stop
// we distinguish multiple dat files by emu start time
time_t start_time = time(NULL);
#endif
while (!Verilated::gotFinish() && trapCode == STATE_RUNNING) { while (!Verilated::gotFinish() && trapCode == STATE_RUNNING) {
if (!(max_cycle > 0 && max_instr > 0 && instr_left_last_cycle >= max_instr /* handle overflow */)) { if (!(max_cycle > 0 && max_instr > 0 && instr_left_last_cycle >= max_instr /* handle overflow */)) {
trapCode = STATE_LIMIT_EXCEEDED; trapCode = STATE_LIMIT_EXCEEDED;
...@@ -334,6 +341,11 @@ uint64_t Emulator::execute(uint64_t max_cycle, uint64_t max_instr) { ...@@ -334,6 +341,11 @@ uint64_t Emulator::execute(uint64_t max_cycle, uint64_t max_instr) {
#if VM_TRACE == 1 #if VM_TRACE == 1
if (enable_waveform) tfp->close(); if (enable_waveform) tfp->close();
#endif #endif
#if VM_COVERAGE == 1
save_coverage(start_time);
#endif
display_trapinfo(); display_trapinfo();
return cycles; return cycles;
} }
...@@ -363,6 +375,22 @@ inline char* Emulator::waveform_filename(time_t t) { ...@@ -363,6 +375,22 @@ inline char* Emulator::waveform_filename(time_t t) {
return buf; return buf;
} }
#if VM_COVERAGE == 1
inline char* Emulator::coverage_filename(time_t t) {
static char buf[1024];
char *p = timestamp_filename(t, buf);
strcpy(p, ".coverage.dat");
return buf;
}
inline void Emulator::save_coverage(time_t t) {
char *p = coverage_filename(t);
VerilatedCov::write(p);
}
#endif
void Emulator::display_trapinfo() { void Emulator::display_trapinfo() {
uint64_t pc = dut_ptr->io_trap_pc; uint64_t pc = dut_ptr->io_trap_pc;
uint64_t instrCnt = dut_ptr->io_trap_instrCnt; uint64_t instrCnt = dut_ptr->io_trap_instrCnt;
......
...@@ -56,9 +56,13 @@ class Emulator { ...@@ -56,9 +56,13 @@ class Emulator {
void display_trapinfo(); void display_trapinfo();
inline char* timestamp_filename(time_t t, char *buf); inline char* timestamp_filename(time_t t, char *buf);
inline char* snapshot_filename(time_t t); inline char* snapshot_filename(time_t t);
inline char* coverage_filename(time_t t);
void snapshot_save(const char *filename); void snapshot_save(const char *filename);
void snapshot_load(const char *filename); void snapshot_load(const char *filename);
inline char* waveform_filename(time_t t); inline char* waveform_filename(time_t t);
#if VM_COVERAGE == 1
inline void save_coverage(time_t t);
#endif
public: public:
Emulator(int argc, const char *argv[]); Emulator(int argc, const char *argv[]);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册