Skip to content

Commit

Permalink
Merge branch 'origin/master' into hardfloat
Browse files Browse the repository at this point in the history
  • Loading branch information
ljwljwljwljw committed Dec 20, 2020
2 parents f4f72af + 77701a7 commit 1a1319c
Show file tree
Hide file tree
Showing 66 changed files with 3,725 additions and 1,728 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/emu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,6 @@ jobs:
- name: Run microbench
run: |
make -C $AM_HOME/apps/microbench ARCH=riscv64-noop AM_HOME=$AM_HOME NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME mainargs=test run 2> /dev/null
- name: Run coremark
run: |
make -C $AM_HOME/apps/coremark ARCH=riscv64-noop AM_HOME=$AM_HOME NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME run 2> /dev/null
4 changes: 2 additions & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[submodule "rocket-chip"]
path = rocket-chip
url = https://github.com/chipsalliance/rocket-chip.git
branch = d6bd3c61993637c3f10544c59e861fae8af29f39
url = https://github.com/RISCVERS/rocket-chip.git
branch = 147bdcc4a26c74e5d7a47e3d667d456699d6d11f
[submodule "block-inclusivecache-sifive"]
path = block-inclusivecache-sifive
url = https://github.com/RISCVERS/block-inclusivecache-sifive.git
Expand Down
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ VEXTRA_FLAGS += --savable
EMU_CXXFLAGS += -DVM_SAVABLE
endif

# Verilator coverage
EMU_COVERAGE ?=
ifeq ($(EMU_COVERAGE),1)
VEXTRA_FLAGS += --coverage-line --coverage-toggle
endif

# co-simulation with DRAMsim3
ifeq ($(WITH_DRAMSIM3),1)
EMU_CXXFLAGS += -I$(DRAMSIM3_HOME)/src
Expand Down Expand Up @@ -167,6 +173,11 @@ emu: $(EMU)
ls build
$(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
# usage: make vme VME_MODULE=Roq
vme: $(SIM_TOP_V)
Expand Down
50 changes: 50 additions & 0 deletions scripts/coverage/coverage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#/usr/bin/python3
# -*- coding: UTF-8 -*-
import sys
import re
import copy

if __name__ == "__main__":
assert len(sys.argv) == 3, "Expect input_file and output_file"
input_file = sys.argv[1]
output_file = sys.argv[2]
lines = []
line_count = 0
synthesis_nest_level = 0
with open(input_file) as f:
for line in f:
line_count += 1

ifdef = re.compile('`ifdef')
ifndef = re.compile('`ifndef')
endif = re.compile('`endif')
synthesis = re.compile('`ifndef SYNTHESIS')
line_coverage = re.compile('^\s*([%]?\d+)\s+if')

ifdef_match = ifdef.search(line)
ifndef_match = ifndef.search(line)
endif_match = endif.search(line)
synthesis_match = synthesis.search(line)
line_coverage_match = line_coverage.search(line)

# enter synthesis block
if synthesis_match:
assert synthesis_nest_level == 0, "Should not nest SYNTHESIS macro"
synthesis_nest_level = 1

if ifdef_match or (ifndef_match and not synthesis_match):
synthesis_nest_level += 1
if endif_match:
synthesis_nest_level -= 1
assert synthesis_nest_level >= 0, "Macro nest level should be >= 0"

# remove line coverage results in systhesis block
if synthesis_nest_level > 0 and line_coverage_match:
coverage_stat = line_coverage_match.group(1)
line = line.replace(line_coverage_match.group(1), " " * len(coverage_stat))

lines += line

with open(output_file, "w") as f:
for line in lines:
f.write(line)
225 changes: 225 additions & 0 deletions scripts/coverage/statistics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
#/usr/bin/python3
# -*- coding: UTF-8 -*-
import sys
import re
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__":
assert len(sys.argv) == 2, "Expect input_file"
input_file = sys.argv[1]
pp = pprint.PrettyPrinter(indent=4)

lines = get_lines(input_file)
# print("lines:")
# pp.pprint(lines)

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)

print("SelfCoverage:")
pp.pprint(sort_coverage(tree_coverage, SELFCOVERAGE))

print("TreeCoverage:")
pp.pprint(sort_coverage(tree_coverage, TREECOVERAGE))

print("AllCoverage:")
print_tree_coverage(tree_coverage)
2 changes: 1 addition & 1 deletion src/main/scala/device/AXI4RAM.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class AXI4RAM
val mems = (0 until split).map {_ => Module(new RAMHelper(bankByte))}
mems.zipWithIndex map { case (mem, i) =>
mem.io.clk := clock
mem.io.en := !reset.asBool() && (state === s_rdata)
mem.io.en := !reset.asBool() && ((state === s_rdata) || (state === s_wdata))
mem.io.rIdx := (rIdx << log2Up(split)) + i.U
mem.io.wIdx := (wIdx << log2Up(split)) + i.U
mem.io.wdata := in.w.bits.data((i + 1) * 64 - 1, i * 64)
Expand Down
6 changes: 5 additions & 1 deletion src/main/scala/utils/BitUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,8 @@ object GenMask {
def apply(pos: Int) = {
(1.U << pos).asUInt()
}
}
}

object UIntToMask {
def apply(ptr: UInt, length: Integer) = UIntToOH(ptr)(length - 1, 0) - 1.U
}
27 changes: 25 additions & 2 deletions src/main/scala/utils/ParallelMux.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import chisel3._
import chisel3.util._

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)
xs match {
case Seq(a) => a
Expand All @@ -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 {
def apply[T <: Data](xs: Seq[T]): T = {
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 {
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) }
Expand All @@ -50,4 +60,17 @@ object ParallelMin {
def apply[T <: Data](xs: Seq[T]): T = {
ParallelOperation(xs, (a: T, b:T) => Mux(a.asUInt() < b.asUInt(),a, b).asTypeOf(xs.head))
}
}
}

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)
}
Loading

0 comments on commit 1a1319c

Please sign in to comment.