提交 1d975383 编写于 作者: Y Yinan Xu

Merge remote-tracking branch 'origin/master' into perf-debug

...@@ -36,7 +36,7 @@ jobs: ...@@ -36,7 +36,7 @@ jobs:
t=${test%.c} t=${test%.c}
echo $t echo $t
make -C $CPU_TEST_DIR ALL=$t ARCH=riscv64-noop AM_HOME=$AM_HOME NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME run 2>/dev/null | grep "HIT GOOD TRAP" make -C $CPU_TEST_DIR ALL=$t ARCH=riscv64-noop AM_HOME=$AM_HOME NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME run 2>/dev/null | grep "HIT GOOD TRAP"
if [[ $? == 1 ]]; if [[ $? != 0 ]];
then then
echo $t fail echo $t fail
ret=1 ret=1
...@@ -49,3 +49,6 @@ jobs: ...@@ -49,3 +49,6 @@ jobs:
- name: Run microbench - name: Run microbench
run: | 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 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
...@@ -56,7 +56,7 @@ $(SIM_TOP_V): $(SCALA_FILE) $(TEST_FILE) ...@@ -56,7 +56,7 @@ $(SIM_TOP_V): $(SCALA_FILE) $(TEST_FILE)
date -R date -R
mill XiangShan.test.runMain $(SIMTOP) -X verilog -td $(@D) --full-stacktrace --output-file $(@F) $(SIM_ARGS) mill XiangShan.test.runMain $(SIMTOP) -X verilog -td $(@D) --full-stacktrace --output-file $(@F) $(SIM_ARGS)
sed -i '/module XSSimTop/,/endmodule/d' $(SIM_TOP_V) sed -i '/module XSSimTop/,/endmodule/d' $(SIM_TOP_V)
sed -i -e 's/$$fatal/$$finish/g' $(SIM_TOP_V) sed -i -e 's/$$fatal/xs_assert(`__LINE__)/g' $(SIM_TOP_V)
date -R date -R
EMU_TOP = XSSimSoC EMU_TOP = XSSimSoC
...@@ -80,7 +80,7 @@ endif ...@@ -80,7 +80,7 @@ endif
# Verilator multi-thread support # Verilator multi-thread support
EMU_THREADS ?= 1 EMU_THREADS ?= 1
ifneq ($(EMU_THREADS),1) ifneq ($(EMU_THREADS),1)
VEXTRA_FLAGS += --threads $(EMU_THREADS) --threads-dpi none VEXTRA_FLAGS += --threads $(EMU_THREADS) --threads-dpi all
endif endif
# Verilator savable # Verilator savable
...@@ -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)
......
Subproject commit 5adff60abb929cce2e261f1c43c29d8fa40334f9 Subproject commit 3f80e021cffd8c8e61337afb7e8532a2ceb303eb
...@@ -7,8 +7,8 @@ do ...@@ -7,8 +7,8 @@ do
t=${test%.c} t=${test%.c}
echo -n -e "\x1b[0m $t: " echo -n -e "\x1b[0m $t: "
make -C $TEST_HOME ARCH=riscv64-noop E=0 ALL=$t run 2>/dev/null | grep -E "HIT GOOD TRAP|IPC" make -C $TEST_HOME ARCH=riscv64-noop E=0 ALL=$t run 2>/dev/null | grep -E "HIT GOOD TRAP|IPC"
if [[ $? == 1 ]]; if [[ $? != 0 ]];
then then
echo -e "\x1b[31mfail" echo -e "\x1b[31mfail: trap code $?"
fi fi
done done
Subproject commit 147bdcc4a26c74e5d7a47e3d667d456699d6d11f Subproject commit 9cf18f1173443e2542990c090a69bdd62d26228d
#/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
reg_init_nest_level = 0
mem_init_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')
# remove the line coverage results of not synthesizable code(mostly assert and fwrite)
synthesis = re.compile('`ifndef SYNTHESIS')
# remove the coverage results of random init variables
reg_init = re.compile('`ifdef RANDOMIZE_REG_INIT')
mem_init = re.compile('`ifdef RANDOMIZE_MEM_INIT')
coverage = re.compile('^\s*(%?\d+)\s+')
ifdef_match = ifdef.search(line)
ifndef_match = ifndef.search(line)
endif_match = endif.search(line)
synthesis_match = synthesis.search(line)
reg_init_match = reg_init.search(line)
mem_init_match = mem_init.search(line)
coverage_match = coverage.search(line)
# enter synthesis block
if synthesis_match:
assert synthesis_nest_level == 0, "Should not nest SYNTHESIS macro"
synthesis_nest_level = 1
if synthesis_nest_level > 0:
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 coverage_match:
coverage_stat = coverage_match.group(1)
line = line.replace(coverage_match.group(1), " " * len(coverage_stat))
# enter reg_init block
if reg_init_match:
assert reg_init_nest_level == 0, "Should not nest reg_init macro"
reg_init_nest_level = 1
if reg_init_nest_level > 0:
if (ifdef_match and not reg_init_match) or ifndef_match:
reg_init_nest_level += 1
if endif_match:
reg_init_nest_level -= 1
assert reg_init_nest_level >= 0, "Macro nest level should be >= 0"
# remove line coverage results in systhesis block
if coverage_match:
coverage_stat = coverage_match.group(1)
line = line.replace(coverage_match.group(1), " " * len(coverage_stat))
# enter mem_init block
if mem_init_match:
assert mem_init_nest_level == 0, "Should not nest mem_init macro"
mem_init_nest_level = 1
if mem_init_nest_level > 0:
if (ifdef_match and not mem_init_match) or ifndef_match:
mem_init_nest_level += 1
if endif_match:
mem_init_nest_level -= 1
assert mem_init_nest_level >= 0, "Macro nest level should be >= 0"
# remove line coverage results in systhesis block
if coverage_match:
coverage_stat = coverage_match.group(1)
line = line.replace(coverage_match.group(1), " " * len(coverage_stat))
lines += line
with open(output_file, "w") as f:
for line in lines:
f.write(line)
#/usr/bin/python3
# -*- coding: UTF-8 -*-
import sys
import re
import copy
import pprint
LINE_COVERRED = "LINE_COVERRED"
NOT_LINE_COVERRED = "NOT_LINE_COVERRED"
TOGGLE_COVERRED = "TOGGLE_COVERRED"
NOT_TOGGLE_COVERRED = "NOT_TOGGLE_COVERRED"
DONTCARE = "DONTCARE"
BEGIN = "BEGIN"
END = "END"
CHILDREN = "CHILDREN"
MODULE = "MODULE"
INSTANCE = "INSTANCE"
TYPE = "TYPE"
ROOT = "ROOT"
NODE = "NODE"
SELFCOVERAGE = "SELFCOVERAGE"
TREECOVERAGE = "TREECOVERAGE"
LINECOVERAGE = 0
TOGGLECOVERAGE = 1
def check_one_hot(l):
cnt = 0
for e in l:
if e:
cnt += 1
return cnt <= 1
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
line_coverred_pattern_1 = re.compile('^\s*(\d+)\s+if')
line_coverred_pattern_2 = re.compile('^\s*(\d+)\s+end else')
not_line_coverred_pattern_1 = re.compile('^\s*(%0+)\s+if')
not_line_coverred_pattern_2 = re.compile('^\s*(%0+)\s+end else')
toggle_coverred_pattern_1 = re.compile('^\s*(\d+)\s+reg')
toggle_coverred_pattern_2 = re.compile('^\s*(\d+)\s+wire')
toggle_coverred_pattern_3 = re.compile('^\s*(\d+)\s+input')
toggle_coverred_pattern_4 = re.compile('^\s*(\d+)\s+output')
not_toggle_coverred_pattern_1 = re.compile('^\s*(%0+)\s+reg')
not_toggle_coverred_pattern_2 = re.compile('^\s*(%0+)\s+wire')
not_toggle_coverred_pattern_3 = re.compile('^\s*(%0+)\s+input')
not_toggle_coverred_pattern_4 = re.compile('^\s*(%0+)\s+output')
line_cnt = 0
for line in lines:
line_coverred_match = line_coverred_pattern_1.search(line) or line_coverred_pattern_2.search(line)
not_line_coverred_match = not_line_coverred_pattern_1.search(line) or not_line_coverred_pattern_2.search(line)
assert not (line_coverred_match and not_line_coverred_match)
toggle_coverred_match = toggle_coverred_pattern_1.search(line) or toggle_coverred_pattern_2.search(line) or \
toggle_coverred_pattern_3.search(line) or toggle_coverred_pattern_4.search(line)
not_toggle_coverred_match = not_toggle_coverred_pattern_1.search(line) or not_toggle_coverred_pattern_2.search(line) or \
not_toggle_coverred_pattern_3.search(line) or not_toggle_coverred_pattern_4.search(line)
assert not (toggle_coverred_match and not_toggle_coverred_match)
all_match = (line_coverred_match, not_line_coverred_match,
toggle_coverred_match, not_toggle_coverred_match)
if not check_one_hot(all_match):
print("not_one_hot")
print(line_cnt)
print(all_match)
assert False, "This line matches multiple patterns"
if line_coverred_match:
line_annotations.append(LINE_COVERRED)
elif not_line_coverred_match:
line_annotations.append(NOT_LINE_COVERRED)
elif toggle_coverred_match:
line_annotations.append(TOGGLE_COVERRED)
elif not_toggle_coverred_match:
line_annotations.append(NOT_TOGGLE_COVERRED)
else:
line_annotations.append(DONTCARE)
line_cnt += 1
return line_annotations
# get the line coverage statistics in line range [start, end)
def get_coverage_statistics(line_annotations, start, end):
line_coverred = 0
not_line_coverred = 0
toggle_coverred = 0
not_toggle_coverred = 0
for i in range(start, end):
if line_annotations[i] == LINE_COVERRED:
line_coverred += 1
if line_annotations[i] == NOT_LINE_COVERRED:
not_line_coverred += 1
if line_annotations[i] == TOGGLE_COVERRED:
toggle_coverred += 1
if line_annotations[i] == NOT_TOGGLE_COVERRED:
not_toggle_coverred += 1
# deal with divide by zero
line_coverage = 1.0
if line_coverred + not_line_coverred != 0:
line_coverage = float(line_coverred) / (line_coverred + not_line_coverred)
toggle_coverage = 1.0
if toggle_coverred + not_toggle_coverred != 0:
toggle_coverage = float(toggle_coverred) / (toggle_coverred + not_toggle_coverred)
return ((line_coverred, not_line_coverred, line_coverage),
(toggle_coverred, not_toggle_coverred, toggle_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:
line_coverred = self_coverage[LINECOVERAGE][0]
not_line_coverred = self_coverage[LINECOVERAGE][1]
toggle_coverred = self_coverage[TOGGLECOVERAGE][0]
not_toggle_coverred = self_coverage[TOGGLECOVERAGE][1]
# the dfs part
for child in modules[module][CHILDREN]:
child_coverage = dfs(child[MODULE])
line_coverred += child_coverage[LINECOVERAGE][0]
not_line_coverred += child_coverage[LINECOVERAGE][1]
toggle_coverred += child_coverage[TOGGLECOVERAGE][0]
not_toggle_coverred += child_coverage[TOGGLECOVERAGE][1]
# deal with divide by zero
line_coverage = 1.0
if line_coverred + not_line_coverred != 0:
line_coverage = float(line_coverred) / (line_coverred + not_line_coverred)
toggle_coverage = 1.0
if toggle_coverred + not_toggle_coverred != 0:
toggle_coverage = float(toggle_coverred) / (toggle_coverred + not_toggle_coverred)
modules[module][TREECOVERAGE] = ((line_coverred, not_line_coverred, line_coverage),
(toggle_coverred, not_toggle_coverred, toggle_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, self_or_tree, coverage_type):
l = [(module, coverage[module][self_or_tree][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_line", end="")
print("(%d, %d, %.2f)" % (tree[LINECOVERAGE][0], tree[LINECOVERAGE][1], tree[LINECOVERAGE][2] * 100.0))
print(" " * level + " self_line", end="")
print("(%d, %d, %.2f)" % (self[LINECOVERAGE][0], self[LINECOVERAGE][1], self[LINECOVERAGE][2] * 100.0))
print(" " * level + " tree_toggle", end="")
print("(%d, %d, %.2f)" % (tree[TOGGLECOVERAGE][0], tree[TOGGLECOVERAGE][1], tree[TOGGLECOVERAGE][2] * 100.0))
print(" " * level + " self_toggle", end="")
print("(%d, %d, %.2f)" % (self[TOGGLECOVERAGE][0], self[TOGGLECOVERAGE][1], self[TOGGLECOVERAGE][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("LineSelfCoverage:")
pp.pprint(sort_coverage(tree_coverage, SELFCOVERAGE, LINECOVERAGE))
print("LineTreeCoverage:")
pp.pprint(sort_coverage(tree_coverage, TREECOVERAGE, LINECOVERAGE))
print("ToggleSelfCoverage:")
pp.pprint(sort_coverage(tree_coverage, SELFCOVERAGE, TOGGLECOVERAGE))
print("ToggleTreeCoverage:")
pp.pprint(sort_coverage(tree_coverage, TREECOVERAGE, TOGGLECOVERAGE))
print("AllCoverage:")
print_tree_coverage(tree_coverage)
...@@ -45,6 +45,8 @@ trait HasCircularQueuePtrHelper { ...@@ -45,6 +45,8 @@ trait HasCircularQueuePtrHelper {
} }
final def === (that_ptr: T): Bool = ptr.asUInt()===that_ptr.asUInt() final def === (that_ptr: T): Bool = ptr.asUInt()===that_ptr.asUInt()
final def =/= (that_ptr: T): Bool = ptr.asUInt()=/=that_ptr.asUInt()
} }
......
package utils
import chisel3._
import chisel3.util._
class DataModuleTemplate[T <: Data](gen: T, numEntries: Int, numRead: Int, numWrite: Int, useBitVec: Boolean = false) extends Module {
val io = IO(new Bundle {
val raddr = Vec(numRead, Input(UInt(log2Up(numEntries).W)))
val rdata = Vec(numRead, Output(gen))
val wen = Vec(numWrite, Input(Bool()))
val waddr = Vec(numWrite, Input(UInt(log2Up(numEntries).W)))
val wdata = Vec(numWrite, Input(gen))
})
val data = Mem(numEntries, gen)
// read ports
for (i <- 0 until numRead) {
io.rdata(i) := data(io.raddr(i))
}
if (useBitVec) {
// waddr_dec(i)(j): waddr(i) is target at entry(j)
val waddr_dec = VecInit(io.waddr.map(UIntToOH(_)(numEntries - 1, 0)))
// waddr_dec_with_en(i)(j): entry(j) is written by io.wdata(i)
val waddr_dec_with_en = VecInit(io.wen.zip(waddr_dec).map{case (en, addr) => Fill(numEntries, en) & addr})
val wen_dec = VecInit((0 until numEntries).map(j => {
val data_wen = VecInit(waddr_dec_with_en.map(en => en(j)))
data_wen.suggestName(s"data_wen_$j")
data_wen.asUInt.orR
}))
val wdata_dec = VecInit((0 until numEntries).map(j =>
waddr_dec_with_en.zip(io.wdata).map{ case (en, data) => Fill(gen.getWidth, en(j)) & data.asUInt}.reduce(_ | _).asTypeOf(gen)
))
waddr_dec.suggestName("waddr_dec")
waddr_dec_with_en.suggestName("waddr_dec_with_en")
wen_dec.suggestName("wen_dec")
wdata_dec.suggestName("wdata_dec")
// write ports
for (i <- 0 until numEntries) {
when (wen_dec(i)) {
data(i) := wdata_dec(i)
}
}
}
else {
// below is the write ports (with priorities)
for (i <- 0 until numWrite) {
when (io.wen(i)) {
data(io.waddr(i)) := io.wdata(i)
}
}
}
// DataModuleTemplate should not be used when there're any write conflicts
for (i <- 0 until numWrite) {
for (j <- i+1 until numWrite) {
assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j)))
}
}
}
...@@ -31,7 +31,7 @@ class DebugIdentityNode()(implicit p: Parameters) extends LazyModule { ...@@ -31,7 +31,7 @@ class DebugIdentityNode()(implicit p: Parameters) extends LazyModule {
} }
) )
} }
debug(in, true) debug(in, false)
} }
} }
......
...@@ -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)
}
...@@ -6,6 +6,7 @@ import chisel3.util._ ...@@ -6,6 +6,7 @@ import chisel3.util._
object PipelineConnect { object PipelineConnect {
def apply[T <: Data](left: DecoupledIO[T], right: DecoupledIO[T], rightOutFire: Bool, isFlush: Bool) = { def apply[T <: Data](left: DecoupledIO[T], right: DecoupledIO[T], rightOutFire: Bool, isFlush: Bool) = {
val valid = RegInit(false.B) val valid = RegInit(false.B)
valid.suggestName("pipeline_valid")
when (rightOutFire) { valid := false.B } when (rightOutFire) { valid := false.B }
when (left.valid && right.ready) { valid := true.B } when (left.valid && right.ready) { valid := true.B }
when (isFlush) { valid := false.B } when (isFlush) { valid := false.B }
......
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
package utils package utils
import chisel3._ import chisel3._
import chisel3.util._
import freechips.rocketchip.tilelink.TLMessages._
import freechips.rocketchip.tilelink.TLPermissions._
import freechips.rocketchip.tilelink.{TLBundle, TLBundleA, TLBundleB, TLBundleC, TLBundleD, TLBundleE, TLChannel} import freechips.rocketchip.tilelink.{TLBundle, TLBundleA, TLBundleB, TLBundleC, TLBundleD, TLBundleE, TLChannel}
import xiangshan.HasXSLog import xiangshan.HasXSLog
trait HasTLDump { this: HasXSLog => trait HasTLDump {
this: HasXSLog =>
implicit class TLDump(channel: TLChannel) { implicit class TLDump(channel: TLChannel) {
def dump = channel match { def dump = channel match {
case a: TLBundleA => case a: TLBundleA =>
printChannelA(a)
case b: TLBundleB =>
printChannelB(b)
case c: TLBundleC =>
printChannelC(c)
case d: TLBundleD =>
printChannelD(d)
case e: TLBundleE =>
printChannelE(e)
}
}
def printChannelA(a: TLBundleA): Unit = {
switch(a.opcode) {
is(PutFullData) {
XSDebug(false, true.B, XSDebug(false, true.B,
a.channelName + " opcode: %x param: %x size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n", a.channelName + " PutFullData param: %x size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
a.opcode, a.param, a.size, a.source, a.address, a.mask, a.data, a.corrupt a.param, a.size, a.source, a.address, a.mask, a.data, a.corrupt
) )
case b: TLBundleB => }
is(PutPartialData) {
XSDebug(false, true.B, XSDebug(false, true.B,
b.channelName + " opcode: %x param: %x size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n", a.channelName + " PutPartialData param: %x size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
b.opcode, b.param, b.size, b.source, b.address, b.mask, b.data, b.corrupt a.param, a.size, a.source, a.address, a.mask, a.data, a.corrupt
) )
case c: TLBundleC => }
is(ArithmeticData) {
XSDebug(false, true.B, XSDebug(false, true.B,
c.channelName + " opcode: %x param: %x size: %x source: %d address: %x data: %x corrupt: %b\n", a.channelName + " ArithmeticData param: %x size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
c.opcode, c.param, c.size, c.source, c.address, c.data, c.corrupt a.param, a.size, a.source, a.address, a.mask, a.data, a.corrupt
) )
case d: TLBundleD => }
is(LogicalData) {
XSDebug(false, true.B, XSDebug(false, true.B,
d.channelName + " opcode: %x param: %x size: %x source: %d sink: %d denied: %b data: %x corrupt: %b\n", a.channelName + " LogicalData param: %x size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
d.opcode, d.param, d.size, d.source, d.sink, d.denied, d.data, d.corrupt a.param, a.size, a.source, a.address, a.mask, a.data, a.corrupt
) )
case e: TLBundleE => }
XSDebug(false, true.B, e.channelName + " sink: %d\n", e.sink)
is(Get) {
XSDebug(false, true.B,
a.channelName + " Get param: %x size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
a.param, a.size, a.source, a.address, a.mask, a.data, a.corrupt
)
}
is(Hint) {
XSDebug(false, true.B,
a.channelName + " Intent param: %x size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
a.param, a.size, a.source, a.address, a.mask, a.data, a.corrupt
)
}
is(AcquireBlock) {
switch(a.param) {
is(NtoB) {
XSDebug(false, true.B,
a.channelName + " AcquireBlock NtoB size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
a.size, a.source, a.address, a.mask, a.data, a.corrupt
)
}
is(NtoT) {
XSDebug(false, true.B,
a.channelName + " AcquireBlock NtoT size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
a.size, a.source, a.address, a.mask, a.data, a.corrupt
)
}
is(BtoT) {
XSDebug(false, true.B,
a.channelName + " AcquireBlock BtoT size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
a.size, a.source, a.address, a.mask, a.data, a.corrupt
)
}
}
}
is(AcquirePerm) {
switch(a.param) {
is(NtoB) {
XSDebug(false, true.B,
a.channelName + " AcquirePerm NtoB size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
a.size, a.source, a.address, a.mask, a.data, a.corrupt
)
}
is(NtoT) {
XSDebug(false, true.B,
a.channelName + " AcquirePerm NtoT size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
a.size, a.source, a.address, a.mask, a.data, a.corrupt
)
}
is(BtoT) {
XSDebug(false, true.B,
a.channelName + " AcquirePerm BtoT size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
a.size, a.source, a.address, a.mask, a.data, a.corrupt
)
}
}
}
} }
} }
def printChannelB(b: TLBundleB): Unit = {
switch(b.opcode) {
is(PutFullData) {
XSDebug(false, true.B,
b.channelName + " PutFullData param: %x size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
b.param, b.size, b.source, b.address, b.mask, b.data, b.corrupt
)
}
is(PutPartialData) {
XSDebug(false, true.B,
b.channelName + " PutPartialData param: %x size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
b.param, b.size, b.source, b.address, b.mask, b.data, b.corrupt
)
}
is(ArithmeticData) {
XSDebug(false, true.B,
b.channelName + " ArithmeticData param: %x size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
b.param, b.size, b.source, b.address, b.mask, b.data, b.corrupt
)
}
is(LogicalData) {
XSDebug(false, true.B,
b.channelName + " LogicalData param: %x size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
b.param, b.size, b.source, b.address, b.mask, b.data, b.corrupt
)
}
is(Get) {
XSDebug(false, true.B,
b.channelName + " Get param: %x size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
b.param, b.size, b.source, b.address, b.mask, b.data, b.corrupt
)
}
is(Hint) {
XSDebug(false, true.B,
b.channelName + " Intent param: %x size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
b.param, b.size, b.source, b.address, b.mask, b.data, b.corrupt
)
}
is(Probe) {
switch(b.param) {
is(toN) {
XSDebug(false, true.B,
b.channelName + " Probe toN size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
b.size, b.source, b.address, b.mask, b.data, b.corrupt
)
}
is(toB) {
XSDebug(false, true.B,
b.channelName + " Probe toB size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
b.size, b.source, b.address, b.mask, b.data, b.corrupt
)
}
is(toT) {
XSDebug(false, true.B,
b.channelName + " Probe toT size: %x source: %d address: %x mask: %x data: %x corrupt: %b\n",
b.size, b.source, b.address, b.mask, b.data, b.corrupt
)
}
}
}
}
}
def printChannelC(c: TLBundleC): Unit = {
switch(c.opcode) {
is(AccessAck) {
XSDebug(false, true.B,
c.channelName + " AccessAck param: %x size: %x source: %d address: %x data: %x corrupt: %b\n",
c.param, c.size, c.source, c.address, c.data, c.corrupt
)
}
is(AccessAckData) {
XSDebug(false, true.B,
c.channelName + " AccessAckData param: %x size: %x source: %d address: %x data: %x corrupt: %b\n",
c.param, c.size, c.source, c.address, c.data, c.corrupt
)
}
is(HintAck) {
XSDebug(false, true.B,
c.channelName + " HintAck param: %x size: %x source: %d address: %x data: %x corrupt: %b\n",
c.param, c.size, c.source, c.address, c.data, c.corrupt
)
}
is(ProbeAck) {
switch(c.param) {
is(TtoB) {
XSDebug(false, true.B,
c.channelName + " ProbeAck TtoB size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
is(TtoN) {
XSDebug(false, true.B,
c.channelName + " ProbeAck TtoN size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
is(BtoN) {
XSDebug(false, true.B,
c.channelName + " ProbeAck BtoN size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
is(TtoT) {
XSDebug(false, true.B,
c.channelName + " ProbeAck TtoT size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
is(BtoB) {
XSDebug(false, true.B,
c.channelName + " ProbeAck BtoB size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
is(NtoN) {
XSDebug(false, true.B,
c.channelName + " ProbeAck NtoN size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
}
}
is(ProbeAckData) {
switch(c.param) {
is(TtoB) {
XSDebug(false, true.B,
c.channelName + " ProbeAckData TtoB size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
is(TtoN) {
XSDebug(false, true.B,
c.channelName + " ProbeAckData TtoN size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
is(BtoN) {
XSDebug(false, true.B,
c.channelName + " ProbeAckData BtoN size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
is(TtoT) {
XSDebug(false, true.B,
c.channelName + " ProbeAckData TtoT size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
is(BtoB) {
XSDebug(false, true.B,
c.channelName + " ProbeAckData BtoB size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
is(NtoN) {
XSDebug(false, true.B,
c.channelName + " ProbeAckData NtoN size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
}
}
is(Release) {
switch(c.param) {
is(TtoB) {
XSDebug(false, true.B,
c.channelName + " Release TtoB size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
is(TtoN) {
XSDebug(false, true.B,
c.channelName + " Release TtoN size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
is(BtoN) {
XSDebug(false, true.B,
c.channelName + " Release BtoN size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
is(TtoT) {
XSDebug(false, true.B,
c.channelName + " Release TtoT size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
is(BtoB) {
XSDebug(false, true.B,
c.channelName + " Release BtoB size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
is(NtoN) {
XSDebug(false, true.B,
c.channelName + " Release NtoN size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
}
}
is(ReleaseData) {
switch(c.param) {
is(TtoB) {
XSDebug(false, true.B,
c.channelName + " ReleaseData TtoB size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
is(TtoN) {
XSDebug(false, true.B,
c.channelName + " ReleaseData TtoN size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
is(BtoN) {
XSDebug(false, true.B,
c.channelName + " ReleaseData BtoN size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
is(TtoT) {
XSDebug(false, true.B,
c.channelName + " ReleaseData TtoT size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
is(BtoB) {
XSDebug(false, true.B,
c.channelName + " ReleaseData BtoB size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
is(NtoN) {
XSDebug(false, true.B,
c.channelName + " ReleaseData NtoN size: %x source: %d address: %x data: %x corrupt: %b\n",
c.size, c.source, c.address, c.data, c.corrupt
)
}
}
}
}
}
def printChannelD(d: TLBundleD): Unit = {
switch(d.opcode) {
is(AccessAck) {
XSDebug(false, true.B,
d.channelName + " AccessAck param: %x size: %x source: %d sink: %d denied: %b data: %x corrupt: %b\n",
d.param, d.size, d.source, d.sink, d.denied, d.data, d.corrupt
)
}
is(AccessAckData) {
XSDebug(false, true.B,
d.channelName + " AccessAckData param: %x size: %x source: %d sink: %d denied: %b data: %x corrupt: %b\n",
d.param, d.size, d.source, d.sink, d.denied, d.data, d.corrupt
)
}
is(HintAck) {
XSDebug(false, true.B,
d.channelName + " HintAck param: %x size: %x source: %d sink: %d denied: %b data: %x corrupt: %b\n",
d.param, d.size, d.source, d.sink, d.denied, d.data, d.corrupt
)
}
is(Grant) {
switch(d.param) {
is(toT) {
XSDebug(false, true.B,
d.channelName + " Grant toT size: %x source: %d sink: %d denied: %b data: %x corrupt: %b\n",
d.size, d.source, d.sink, d.denied, d.data, d.corrupt
)
}
is(toB) {
XSDebug(false, true.B,
d.channelName + " Grant toB size: %x source: %d sink: %d denied: %b data: %x corrupt: %b\n",
d.size, d.source, d.sink, d.denied, d.data, d.corrupt
)
}
is(toN) {
XSDebug(false, true.B,
d.channelName + " Grant toN size: %x source: %d sink: %d denied: %b data: %x corrupt: %b\n",
d.size, d.source, d.sink, d.denied, d.data, d.corrupt
)
}
}
}
is(GrantData) {
switch(d.param) {
is(toT) {
XSDebug(false, true.B,
d.channelName + " GrantData toT size: %x source: %d sink: %d denied: %b data: %x corrupt: %b\n",
d.size, d.source, d.sink, d.denied, d.data, d.corrupt
)
}
is(toB) {
XSDebug(false, true.B,
d.channelName + " GrantData toB size: %x source: %d sink: %d denied: %b data: %x corrupt: %b\n",
d.size, d.source, d.sink, d.denied, d.data, d.corrupt
)
}
is(toN) {
XSDebug(false, true.B,
d.channelName + " GrantData toN size: %x source: %d sink: %d denied: %b data: %x corrupt: %b\n",
d.size, d.source, d.sink, d.denied, d.data, d.corrupt
)
}
}
}
is(ReleaseAck) {
XSDebug(false, true.B,
d.channelName + " ReleaseAck param: %x size: %x source: %d sink: %d denied: %b data: %x corrupt: %b\n",
d.param, d.size, d.source, d.sink, d.denied, d.data, d.corrupt
)
}
}
}
def printChannelE(e: TLBundleE): Unit = {
XSDebug(false, true.B, e.channelName + "GrantAck sink: %d\n", e.sink)
}
} }
...@@ -2,15 +2,18 @@ package xiangshan ...@@ -2,15 +2,18 @@ package xiangshan
import chisel3._ import chisel3._
import chisel3.util._ import chisel3.util._
import xiangshan.backend.SelImm
import xiangshan.backend.brq.BrqPtr import xiangshan.backend.brq.BrqPtr
import xiangshan.backend.fu.fpu.Fflags import xiangshan.backend.fu.fpu.Fflags
import xiangshan.backend.rename.FreeListPtr import xiangshan.backend.rename.FreeListPtr
import xiangshan.backend.roq.RoqPtr import xiangshan.backend.roq.RoqPtr
import xiangshan.backend.decode.XDecode
import xiangshan.mem.{LqPtr, SqPtr} import xiangshan.mem.{LqPtr, SqPtr}
import xiangshan.frontend.PreDecodeInfo import xiangshan.frontend.PreDecodeInfo
import xiangshan.frontend.HasBPUParameter import xiangshan.frontend.HasBPUParameter
import xiangshan.frontend.HasTageParameter import xiangshan.frontend.HasTageParameter
import xiangshan.frontend.HasIFUConst import xiangshan.frontend.HasIFUConst
import xiangshan.frontend.GlobalHistory
import utils._ import utils._
import scala.math.max import scala.math.max
...@@ -18,10 +21,11 @@ import scala.math.max ...@@ -18,10 +21,11 @@ import scala.math.max
class FetchPacket extends XSBundle { class FetchPacket extends XSBundle {
val instrs = Vec(PredictWidth, UInt(32.W)) val instrs = Vec(PredictWidth, UInt(32.W))
val mask = UInt(PredictWidth.W) val mask = UInt(PredictWidth.W)
val pdmask = UInt(PredictWidth.W)
// val pc = UInt(VAddrBits.W) // val pc = UInt(VAddrBits.W)
val pc = Vec(PredictWidth, UInt(VAddrBits.W)) val pc = Vec(PredictWidth, UInt(VAddrBits.W))
val pnpc = Vec(PredictWidth, UInt(VAddrBits.W)) val pnpc = Vec(PredictWidth, UInt(VAddrBits.W))
val brInfo = Vec(PredictWidth, new BranchInfo) val bpuMeta = Vec(PredictWidth, new BpuMeta)
val pd = Vec(PredictWidth, new PreDecodeInfo) val pd = Vec(PredictWidth, new PreDecodeInfo)
val ipf = Bool() val ipf = Bool()
val acf = Bool() val acf = Bool()
...@@ -79,15 +83,12 @@ class BranchPrediction extends XSBundle with HasIFUConst { ...@@ -79,15 +83,12 @@ class BranchPrediction extends XSBundle with HasIFUConst {
val firstBankHasHalfRVI = Bool() val firstBankHasHalfRVI = Bool()
val lastBankHasHalfRVI = Bool() val lastBankHasHalfRVI = Bool()
def lastHalfRVIMask = Mux(firstBankHasHalfRVI, UIntToOH((bankWidth-1).U), // assumes that only one of the two conditions could be true
Mux(lastBankHasHalfRVI, UIntToOH((PredictWidth-1).U), def lastHalfRVIMask = Cat(lastBankHasHalfRVI.asUInt, 0.U(7.W), firstBankHasHalfRVI.asUInt, 0.U(7.W))
0.U(PredictWidth.W)
)
)
def lastHalfRVIClearMask = ~lastHalfRVIMask def lastHalfRVIClearMask = ~lastHalfRVIMask
// is taken from half RVI // is taken from half RVI
def lastHalfRVITaken = (takens & lastHalfRVIMask).orR def lastHalfRVITaken = (takens(bankWidth-1) && firstBankHasHalfRVI) || (takens(PredictWidth-1) && lastBankHasHalfRVI)
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
...@@ -97,48 +98,52 @@ class BranchPrediction extends XSBundle with HasIFUConst { ...@@ -97,48 +98,52 @@ class BranchPrediction extends XSBundle with HasIFUConst {
def realBrMask = brMask & lastHalfRVIClearMask def realBrMask = brMask & lastHalfRVIClearMask
def realJalMask = jalMask & lastHalfRVIClearMask def realJalMask = jalMask & lastHalfRVIClearMask
def brNotTakens = ~realTakens & realBrMask def brNotTakens = ~takens & 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))) || // if not taken before the half RVI inst
(lastBankHasHalfRVI && unmaskedJmpIdx === (PredictWidth-1).U) def saveHalfRVI = (firstBankHasHalfRVI && !(ParallelORR(takens(bankWidth-2,0)))) ||
(lastBankHasHalfRVI && !(ParallelORR(takens(PredictWidth-2,0))))
// 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, ParallelPriorityMux(realTakens, sawNotTakenBr), ParallelORR(brNotTakens))
} }
class BranchInfo extends XSBundle with HasBPUParameter { class BpuMeta extends XSBundle with HasBPUParameter {
val ubtbWriteWay = UInt(log2Up(UBtbWays).W) val ubtbWriteWay = UInt(log2Up(UBtbWays).W)
val ubtbHits = Bool() val ubtbHits = Bool()
val btbWriteWay = UInt(log2Up(BtbWays).W) val btbWriteWay = UInt(log2Up(BtbWays).W)
val btbHitJal = Bool() val btbHitJal = Bool()
val bimCtr = UInt(2.W) val bimCtr = UInt(2.W)
val histPtr = UInt(log2Up(ExtHistoryLength).W)
val predHistPtr = UInt(log2Up(ExtHistoryLength).W)
val tageMeta = new TageMeta val tageMeta = new TageMeta
val rasSp = UInt(log2Up(RasSize).W) val rasSp = UInt(log2Up(RasSize).W)
val rasTopCtr = UInt(8.W) val rasTopCtr = UInt(8.W)
val rasToqAddr = UInt(VAddrBits.W) val rasToqAddr = UInt(VAddrBits.W)
val fetchIdx = UInt(log2Up(PredictWidth).W) val fetchIdx = UInt(log2Up(PredictWidth).W)
val specCnt = UInt(10.W) val specCnt = UInt(10.W)
// for global history
val predTaken = Bool()
val hist = new GlobalHistory
val predHist = new GlobalHistory
val sawNotTakenBranch = Bool() val sawNotTakenBranch = Bool()
val debug_ubtb_cycle = if (EnableBPUTimeRecord) UInt(64.W) else UInt(0.W) val debug_ubtb_cycle = if (EnableBPUTimeRecord) UInt(64.W) else UInt(0.W)
val debug_btb_cycle = if (EnableBPUTimeRecord) UInt(64.W) else UInt(0.W) val debug_btb_cycle = if (EnableBPUTimeRecord) UInt(64.W) else UInt(0.W)
val debug_tage_cycle = if (EnableBPUTimeRecord) UInt(64.W) else UInt(0.W) val debug_tage_cycle = if (EnableBPUTimeRecord) UInt(64.W) else UInt(0.W)
def apply(histPtr: UInt, tageMeta: TageMeta, rasSp: UInt, rasTopCtr: UInt) = { // def apply(histPtr: UInt, tageMeta: TageMeta, rasSp: UInt, rasTopCtr: UInt) = {
this.histPtr := histPtr // this.histPtr := histPtr
this.tageMeta := tageMeta // this.tageMeta := tageMeta
this.rasSp := rasSp // this.rasSp := rasSp
this.rasTopCtr := rasTopCtr // this.rasTopCtr := rasTopCtr
this.asUInt // this.asUInt
} // }
def size = 0.U.asTypeOf(this).getWidth def size = 0.U.asTypeOf(this).getWidth
def fromUInt(x: UInt) = x.asTypeOf(this) def fromUInt(x: UInt) = x.asTypeOf(this)
} }
...@@ -150,20 +155,22 @@ class Predecode extends XSBundle with HasIFUConst { ...@@ -150,20 +155,22 @@ class Predecode extends XSBundle with HasIFUConst {
val pd = Vec(FetchWidth*2, (new PreDecodeInfo)) val pd = Vec(FetchWidth*2, (new PreDecodeInfo))
} }
class BranchUpdateInfo extends XSBundle { class CfiUpdateInfo extends XSBundle {
// from backend // from backend
val pc = UInt(VAddrBits.W) val pc = UInt(VAddrBits.W)
val pnpc = UInt(VAddrBits.W) val pnpc = UInt(VAddrBits.W)
val fetchIdx = UInt(log2Up(FetchWidth*2).W)
// frontend -> backend -> frontend
val pd = new PreDecodeInfo
val bpuMeta = new BpuMeta
// need pipeline update
val target = UInt(VAddrBits.W) val target = UInt(VAddrBits.W)
val brTarget = UInt(VAddrBits.W) val brTarget = UInt(VAddrBits.W)
val taken = Bool() val taken = Bool()
val fetchIdx = UInt(log2Up(FetchWidth*2).W)
val isMisPred = Bool() val isMisPred = Bool()
val brTag = new BrqPtr val brTag = new BrqPtr
val isReplay = Bool()
// frontend -> backend -> frontend
val pd = new PreDecodeInfo
val brInfo = new BranchInfo
} }
// Dequeue DecodeWidth insts from Ibuffer // Dequeue DecodeWidth insts from Ibuffer
...@@ -172,7 +179,7 @@ class CtrlFlow extends XSBundle { ...@@ -172,7 +179,7 @@ class CtrlFlow extends XSBundle {
val pc = UInt(VAddrBits.W) val pc = UInt(VAddrBits.W)
val exceptionVec = Vec(16, Bool()) val exceptionVec = Vec(16, Bool())
val intrVec = Vec(12, Bool()) val intrVec = Vec(12, Bool())
val brUpdate = new BranchUpdateInfo val brUpdate = new CfiUpdateInfo
val crossPageIPFFix = Bool() val crossPageIPFFix = Bool()
} }
...@@ -190,8 +197,19 @@ class CtrlSignals extends XSBundle { ...@@ -190,8 +197,19 @@ class CtrlSignals extends XSBundle {
val blockBackward = Bool() // block backward val blockBackward = Bool() // block backward
val flushPipe = Bool() // This inst will flush all the pipe when commit, like exception but can commit val flushPipe = Bool() // This inst will flush all the pipe when commit, like exception but can commit
val isRVF = Bool() val isRVF = Bool()
val selImm = SelImm()
val imm = UInt(XLEN.W) val imm = UInt(XLEN.W)
val commitType = CommitType() val commitType = CommitType()
def decode(inst: UInt, table: Iterable[(BitPat, List[BitPat])]) = {
val decoder = freechips.rocketchip.rocket.DecodeLogic(inst, XDecode.decodeDefault, table)
val signals =
Seq(src1Type, src2Type, src3Type, fuType, fuOpType, rfWen, fpWen,
isXSTrap, noSpecExec, blockBackward, flushPipe, isRVF, selImm)
signals zip decoder map { case(s, d) => s := d }
commitType := DontCare
this
}
} }
class CfCtrl extends XSBundle { class CfCtrl extends XSBundle {
...@@ -200,7 +218,6 @@ class CfCtrl extends XSBundle { ...@@ -200,7 +218,6 @@ class CfCtrl extends XSBundle {
val brTag = new BrqPtr val brTag = new BrqPtr
} }
class PerfDebugInfo extends XSBundle { class PerfDebugInfo extends XSBundle {
// val fetchTime = UInt(64.W) // val fetchTime = UInt(64.W)
val renameTime = UInt(64.W) val renameTime = UInt(64.W)
...@@ -210,35 +227,34 @@ class PerfDebugInfo extends XSBundle { ...@@ -210,35 +227,34 @@ class PerfDebugInfo extends XSBundle {
// val commitTime = UInt(64.W) // val commitTime = UInt(64.W)
} }
// Load / Store Index // Separate LSQ
// class LSIdx extends XSBundle {
// while separated lq and sq is used, lsIdx consists of lqIdx, sqIdx and l/s type.
trait HasLSIdx { this: HasXSParameter =>
// Separate LSQ
val lqIdx = new LqPtr val lqIdx = new LqPtr
val sqIdx = new SqPtr val sqIdx = new SqPtr
} }
class LSIdx extends XSBundle with HasLSIdx {}
// CfCtrl -> MicroOp at Rename Stage // CfCtrl -> MicroOp at Rename Stage
class MicroOp extends CfCtrl with HasLSIdx { class MicroOp extends CfCtrl {
val psrc1, psrc2, psrc3, pdest, old_pdest = UInt(PhyRegIdxWidth.W) val psrc1, psrc2, psrc3, pdest, old_pdest = UInt(PhyRegIdxWidth.W)
val src1State, src2State, src3State = SrcState() val src1State, src2State, src3State = SrcState()
val roqIdx = new RoqPtr val roqIdx = new RoqPtr
val lqIdx = new LqPtr
val sqIdx = new SqPtr
val diffTestDebugLrScValid = Bool() val diffTestDebugLrScValid = Bool()
val debugInfo = new PerfDebugInfo val debugInfo = new PerfDebugInfo
} }
class Redirect extends XSBundle { class Redirect extends XSBundle {
val roqIdx = new RoqPtr val roqIdx = new RoqPtr
val isException = Bool() val level = RedirectLevel()
val isMisPred = Bool() val interrupt = Bool()
val isReplay = Bool()
val isFlushPipe = Bool()
val pc = UInt(VAddrBits.W) val pc = UInt(VAddrBits.W)
val target = UInt(VAddrBits.W) val target = UInt(VAddrBits.W)
val brTag = new BrqPtr val brTag = new BrqPtr
def isUnconditional() = RedirectLevel.isUnconditional(level)
def flushItself() = RedirectLevel.flushItself(level)
def isException() = RedirectLevel.isException(level)
} }
class Dp1ToDp2IO extends XSBundle { class Dp1ToDp2IO extends XSBundle {
...@@ -269,7 +285,7 @@ class ExuOutput extends XSBundle { ...@@ -269,7 +285,7 @@ class ExuOutput extends XSBundle {
val fflags = new Fflags val fflags = new Fflags
val redirectValid = Bool() val redirectValid = Bool()
val redirect = new Redirect val redirect = new Redirect
val brUpdate = new BranchUpdateInfo val brUpdate = new CfiUpdateInfo
val debug = new DebugBundle val debug = new DebugBundle
} }
...@@ -288,18 +304,27 @@ class CSRSpecialIO extends XSBundle { ...@@ -288,18 +304,27 @@ class CSRSpecialIO extends XSBundle {
val interrupt = Output(Bool()) val interrupt = Output(Bool())
} }
//class ExuIO extends XSBundle { class RoqCommitInfo extends XSBundle {
// val in = Flipped(DecoupledIO(new ExuInput)) val ldest = UInt(5.W)
// val redirect = Flipped(ValidIO(new Redirect)) val rfWen = Bool()
// val out = DecoupledIO(new ExuOutput) val fpWen = Bool()
// // for csr val commitType = CommitType()
// val csrOnly = new CSRSpecialIO val pdest = UInt(PhyRegIdxWidth.W)
// val mcommit = Input(UInt(3.W)) val old_pdest = UInt(PhyRegIdxWidth.W)
//} val lqIdx = new LqPtr
val sqIdx = new SqPtr
class RoqCommit extends XSBundle { // these should be optimized for synthesis verilog
val uop = new MicroOp val pc = UInt(VAddrBits.W)
val isWalk = Bool() }
class RoqCommitIO extends XSBundle {
val isWalk = Output(Bool())
val valid = Vec(CommitWidth, Output(Bool()))
val info = Vec(CommitWidth, Output(new RoqCommitInfo))
def hasWalkInstr = isWalk && valid.asUInt.orR
def hasCommitInstr = !isWalk && valid.asUInt.orR
} }
class TlbFeedback extends XSBundle { class TlbFeedback extends XSBundle {
...@@ -312,8 +337,8 @@ class FrontendToBackendIO extends XSBundle { ...@@ -312,8 +337,8 @@ class FrontendToBackendIO extends XSBundle {
val cfVec = Vec(DecodeWidth, DecoupledIO(new CtrlFlow)) val cfVec = Vec(DecodeWidth, DecoupledIO(new CtrlFlow))
// from backend // from backend
val redirect = Flipped(ValidIO(UInt(VAddrBits.W))) val redirect = Flipped(ValidIO(UInt(VAddrBits.W)))
val outOfOrderBrInfo = Flipped(ValidIO(new BranchUpdateInfo)) // val cfiUpdateInfo = Flipped(ValidIO(new CfiUpdateInfo))
val inOrderBrInfo = Flipped(ValidIO(new BranchUpdateInfo)) val cfiUpdateInfo = Flipped(ValidIO(new CfiUpdateInfo))
} }
class TlbCsrBundle extends XSBundle { class TlbCsrBundle extends XSBundle {
......
...@@ -62,7 +62,6 @@ case class XSCoreParameters ...@@ -62,7 +62,6 @@ case class XSCoreParameters
StoreQueueSize: Int = 48, StoreQueueSize: Int = 48,
RoqSize: Int = 192, RoqSize: Int = 192,
dpParams: DispatchParameters = DispatchParameters( dpParams: DispatchParameters = DispatchParameters(
DqEnqWidth = 4,
IntDqSize = 24, IntDqSize = 24,
FpDqSize = 24, FpDqSize = 24,
LsDqSize = 24, LsDqSize = 24,
...@@ -317,20 +316,16 @@ class XSCoreImp(outer: XSCore) extends LazyModuleImp(outer) ...@@ -317,20 +316,16 @@ class XSCoreImp(outer: XSCore) extends LazyModuleImp(outer)
val uncache = outer.uncache.module val uncache = outer.uncache.module
val l1pluscache = outer.l1pluscache.module val l1pluscache = outer.l1pluscache.module
val ptw = outer.ptw.module val ptw = outer.ptw.module
val icache = Module(new ICache)
frontend.io.backend <> ctrlBlock.io.frontend frontend.io.backend <> ctrlBlock.io.frontend
frontend.io.icacheResp <> icache.io.resp
frontend.io.icacheToTlb <> icache.io.tlb
icache.io.req <> frontend.io.icacheReq
icache.io.flush <> frontend.io.icacheFlush
frontend.io.sfence <> integerBlock.io.fenceio.sfence frontend.io.sfence <> integerBlock.io.fenceio.sfence
frontend.io.tlbCsr <> integerBlock.io.csrio.tlb frontend.io.tlbCsr <> integerBlock.io.csrio.tlb
icache.io.mem_acquire <> l1pluscache.io.req frontend.io.icacheMemAcq <> l1pluscache.io.req
l1pluscache.io.resp <> icache.io.mem_grant l1pluscache.io.resp <> frontend.io.icacheMemGrant
l1pluscache.io.flush := icache.io.l1plusflush l1pluscache.io.flush := frontend.io.l1plusFlush
icache.io.fencei := integerBlock.io.fenceio.fencei frontend.io.fencei := integerBlock.io.fenceio.fencei
ctrlBlock.io.fromIntBlock <> integerBlock.io.toCtrlBlock ctrlBlock.io.fromIntBlock <> integerBlock.io.toCtrlBlock
ctrlBlock.io.fromFpBlock <> floatBlock.io.toCtrlBlock ctrlBlock.io.fromFpBlock <> floatBlock.io.toCtrlBlock
......
...@@ -4,7 +4,7 @@ import chisel3._ ...@@ -4,7 +4,7 @@ import chisel3._
import chisel3.util._ import chisel3.util._
import utils._ import utils._
import xiangshan._ import xiangshan._
import xiangshan.backend.decode.{DecodeBuffer, DecodeStage} import xiangshan.backend.decode.DecodeStage
import xiangshan.backend.rename.{Rename, BusyTable} import xiangshan.backend.rename.{Rename, BusyTable}
import xiangshan.backend.brq.Brq import xiangshan.backend.brq.Brq
import xiangshan.backend.dispatch.Dispatch import xiangshan.backend.dispatch.Dispatch
...@@ -12,6 +12,7 @@ import xiangshan.backend.exu._ ...@@ -12,6 +12,7 @@ import xiangshan.backend.exu._
import xiangshan.backend.exu.Exu.exuConfigs import xiangshan.backend.exu.Exu.exuConfigs
import xiangshan.backend.regfile.RfReadPort import xiangshan.backend.regfile.RfReadPort
import xiangshan.backend.roq.{Roq, RoqPtr, RoqCSRIO} import xiangshan.backend.roq.{Roq, RoqPtr, RoqCSRIO}
import xiangshan.mem.LsqEnqIO
class CtrlToIntBlockIO extends XSBundle { class CtrlToIntBlockIO extends XSBundle {
val enqIqCtrl = Vec(exuParameters.IntExuCnt, DecoupledIO(new MicroOp)) val enqIqCtrl = Vec(exuParameters.IntExuCnt, DecoupledIO(new MicroOp))
...@@ -30,11 +31,7 @@ class CtrlToFpBlockIO extends XSBundle { ...@@ -30,11 +31,7 @@ class CtrlToFpBlockIO extends XSBundle {
class CtrlToLsBlockIO extends XSBundle { class CtrlToLsBlockIO extends XSBundle {
val enqIqCtrl = Vec(exuParameters.LsExuCnt, DecoupledIO(new MicroOp)) val enqIqCtrl = Vec(exuParameters.LsExuCnt, DecoupledIO(new MicroOp))
val enqIqData = Vec(exuParameters.LsExuCnt, Output(new ExuInput)) val enqIqData = Vec(exuParameters.LsExuCnt, Output(new ExuInput))
val enqLsq = new Bundle() { val enqLsq = Flipped(new LsqEnqIO)
val canAccept = Input(Bool())
val req = Vec(RenameWidth, ValidIO(new MicroOp))
val resp = Vec(RenameWidth, Input(new LSIdx))
}
val redirect = ValidIO(new Redirect) val redirect = ValidIO(new Redirect)
} }
...@@ -53,14 +50,13 @@ class CtrlBlock extends XSModule with HasCircularQueuePtrHelper { ...@@ -53,14 +50,13 @@ class CtrlBlock extends XSModule with HasCircularQueuePtrHelper {
val exception = ValidIO(new MicroOp) val exception = ValidIO(new MicroOp)
val isInterrupt = Output(Bool()) val isInterrupt = Output(Bool())
// to mem block // to mem block
val commits = Vec(CommitWidth, ValidIO(new RoqCommit)) val commits = new RoqCommitIO
val roqDeqPtr = Output(new RoqPtr) val roqDeqPtr = Output(new RoqPtr)
} }
}) })
val decode = Module(new DecodeStage) val decode = Module(new DecodeStage)
val brq = Module(new Brq) val brq = Module(new Brq)
val decBuf = Module(new DecodeBuffer)
val rename = Module(new Rename) val rename = Module(new Rename)
val dispatch = Module(new Dispatch) val dispatch = Module(new Dispatch)
val intBusyTable = Module(new BusyTable(NRIntReadPorts, NRIntWritePorts)) val intBusyTable = Module(new BusyTable(NRIntReadPorts, NRIntWritePorts))
...@@ -73,33 +69,31 @@ class CtrlBlock extends XSModule with HasCircularQueuePtrHelper { ...@@ -73,33 +69,31 @@ class CtrlBlock extends XSModule with HasCircularQueuePtrHelper {
// When replay and mis-prediction have the same roqIdx, // When replay and mis-prediction have the same roqIdx,
// mis-prediction should have higher priority, since mis-prediction flushes the load instruction. // mis-prediction should have higher priority, since mis-prediction flushes the load instruction.
// Thus, only when mis-prediction roqIdx is after replay roqIdx, replay should be valid. // Thus, only when mis-prediction roqIdx is after replay roqIdx, replay should be valid.
val brqIsAfterLsq = isAfter(brq.io.redirect.bits.roqIdx, io.fromLsBlock.replay.bits.roqIdx) val brqIsAfterLsq = isAfter(brq.io.redirectOut.bits.roqIdx, io.fromLsBlock.replay.bits.roqIdx)
val redirectArb = Mux(io.fromLsBlock.replay.valid && (!brq.io.redirect.valid || brqIsAfterLsq), val redirectArb = Mux(io.fromLsBlock.replay.valid && (!brq.io.redirectOut.valid || brqIsAfterLsq),
io.fromLsBlock.replay.bits, brq.io.redirect.bits) io.fromLsBlock.replay.bits, brq.io.redirectOut.bits)
val redirectValid = roq.io.redirect.valid || brq.io.redirect.valid || io.fromLsBlock.replay.valid val redirectValid = roq.io.redirectOut.valid || brq.io.redirectOut.valid || io.fromLsBlock.replay.valid
val redirect = Mux(roq.io.redirect.valid, roq.io.redirect.bits, redirectArb) val redirect = Mux(roq.io.redirectOut.valid, roq.io.redirectOut.bits, redirectArb)
io.frontend.redirect.valid := redirectValid io.frontend.redirect.valid := RegNext(redirectValid)
io.frontend.redirect.bits := Mux(roq.io.redirect.valid, roq.io.redirect.bits.target, redirectArb.target) io.frontend.redirect.bits := RegNext(Mux(roq.io.redirectOut.valid, roq.io.redirectOut.bits.target, redirectArb.target))
io.frontend.outOfOrderBrInfo <> brq.io.outOfOrderBrInfo io.frontend.cfiUpdateInfo <> brq.io.cfiInfo
io.frontend.inOrderBrInfo <> brq.io.inOrderBrInfo
decode.io.in <> io.frontend.cfVec decode.io.in <> io.frontend.cfVec
decode.io.toBrq <> brq.io.enqReqs decode.io.toBrq <> brq.io.enqReqs
decode.io.brTags <> brq.io.brTags decode.io.brTags <> brq.io.brTags
decode.io.out <> decBuf.io.in
brq.io.roqRedirect <> roq.io.redirect brq.io.redirect.valid <> redirectValid
brq.io.memRedirect.valid := brq.io.redirect.valid || io.fromLsBlock.replay.valid brq.io.redirect.bits <> redirect
brq.io.memRedirect.bits <> redirectArb
brq.io.bcommit <> roq.io.bcommit brq.io.bcommit <> roq.io.bcommit
brq.io.enqReqs <> decode.io.toBrq brq.io.enqReqs <> decode.io.toBrq
brq.io.exuRedirect <> io.fromIntBlock.exuRedirect brq.io.exuRedirectWb <> io.fromIntBlock.exuRedirect
decBuf.io.isWalking := roq.io.commits(0).valid && roq.io.commits(0).bits.isWalk // pipeline between decode and dispatch
decBuf.io.redirect.valid <> redirectValid val lastCycleRedirect = RegNext(redirectValid)
decBuf.io.redirect.bits <> redirect for (i <- 0 until RenameWidth) {
decBuf.io.out <> rename.io.in PipelineConnect(decode.io.out(i), rename.io.in(i), rename.io.in(i).ready, redirectValid || lastCycleRedirect)
}
rename.io.redirect.valid <> redirectValid rename.io.redirect.valid <> redirectValid
rename.io.redirect.bits <> redirect rename.io.redirect.bits <> redirect
...@@ -124,7 +118,7 @@ class CtrlBlock extends XSModule with HasCircularQueuePtrHelper { ...@@ -124,7 +118,7 @@ class CtrlBlock extends XSModule with HasCircularQueuePtrHelper {
dispatch.io.enqIQData <> io.toIntBlock.enqIqData ++ io.toFpBlock.enqIqData ++ io.toLsBlock.enqIqData dispatch.io.enqIQData <> io.toIntBlock.enqIqData ++ io.toFpBlock.enqIqData ++ io.toLsBlock.enqIqData
val flush = redirectValid && (redirect.isException || redirect.isFlushPipe) val flush = redirectValid && RedirectLevel.isUnconditional(redirect.level)
fpBusyTable.io.flush := flush fpBusyTable.io.flush := flush
intBusyTable.io.flush := flush intBusyTable.io.flush := flush
for((wb, setPhyRegRdy) <- io.fromIntBlock.wbRegs.zip(intBusyTable.io.wbPregs)){ for((wb, setPhyRegRdy) <- io.fromIntBlock.wbRegs.zip(intBusyTable.io.wbPregs)){
...@@ -140,10 +134,8 @@ class CtrlBlock extends XSModule with HasCircularQueuePtrHelper { ...@@ -140,10 +134,8 @@ class CtrlBlock extends XSModule with HasCircularQueuePtrHelper {
fpBusyTable.io.rfReadAddr <> dispatch.io.readFpRf.map(_.addr) fpBusyTable.io.rfReadAddr <> dispatch.io.readFpRf.map(_.addr)
fpBusyTable.io.pregRdy <> dispatch.io.fpPregRdy fpBusyTable.io.pregRdy <> dispatch.io.fpPregRdy
roq.io.memRedirect := DontCare roq.io.redirect.valid := brq.io.redirectOut.valid || io.fromLsBlock.replay.valid
roq.io.memRedirect.valid := false.B roq.io.redirect.bits <> redirectArb
roq.io.brqRedirect.valid := brq.io.redirect.valid || io.fromLsBlock.replay.valid
roq.io.brqRedirect.bits <> redirectArb
roq.io.exeWbResults.take(roqWbSize-1).zip( roq.io.exeWbResults.take(roqWbSize-1).zip(
io.fromIntBlock.wbRegs ++ io.fromFpBlock.wbRegs ++ io.fromLsBlock.stOut io.fromIntBlock.wbRegs ++ io.fromFpBlock.wbRegs ++ io.fromLsBlock.stOut
).foreach{ ).foreach{
...@@ -162,9 +154,9 @@ class CtrlBlock extends XSModule with HasCircularQueuePtrHelper { ...@@ -162,9 +154,9 @@ class CtrlBlock extends XSModule with HasCircularQueuePtrHelper {
// roq to int block // roq to int block
io.roqio.toCSR <> roq.io.csr io.roqio.toCSR <> roq.io.csr
io.roqio.exception.valid := roq.io.redirect.valid && roq.io.redirect.bits.isException io.roqio.exception.valid := roq.io.redirectOut.valid && roq.io.redirectOut.bits.isException()
io.roqio.exception.bits := roq.io.exception io.roqio.exception.bits := roq.io.exception
io.roqio.isInterrupt := roq.io.redirect.bits.isFlushPipe io.roqio.isInterrupt := roq.io.redirectOut.bits.interrupt
// roq to mem block // roq to mem block
io.roqio.roqDeqPtr := roq.io.roqDeqPtr io.roqio.roqDeqPtr := roq.io.roqDeqPtr
io.roqio.commits := roq.io.commits io.roqio.commits := roq.io.commits
......
...@@ -53,7 +53,7 @@ class MemBlock ...@@ -53,7 +53,7 @@ class MemBlock
val lsqio = new Bundle { val lsqio = new Bundle {
val exceptionAddr = new ExceptionAddrIO // to csr val exceptionAddr = new ExceptionAddrIO // to csr
val commits = Flipped(Vec(CommitWidth, Valid(new RoqCommit))) // to lsq val commits = Flipped(new RoqCommitIO) // to lsq
val roqDeqPtr = Input(new RoqPtr) // to lsq val roqDeqPtr = Input(new RoqPtr) // to lsq
} }
}) })
...@@ -229,49 +229,67 @@ class MemBlock ...@@ -229,49 +229,67 @@ class MemBlock
assert(!(fenceFlush && atomicsFlush)) assert(!(fenceFlush && atomicsFlush))
sbuffer.io.flush.valid := fenceFlush || atomicsFlush sbuffer.io.flush.valid := fenceFlush || atomicsFlush
// TODO: make 0/1 configurable // AtomicsUnit: AtomicsUnit will override other control signials,
// AtomicsUnit
// AtomicsUnit will override other control signials,
// as atomics insts (LR/SC/AMO) will block the pipeline // as atomics insts (LR/SC/AMO) will block the pipeline
val st0_atomics = reservationStations(2).io.deq.valid && reservationStations(2).io.deq.bits.uop.ctrl.fuType === FuType.mou val s_normal :: s_atomics_0 :: s_atomics_1 :: Nil = Enum(3)
val st1_atomics = reservationStations(3).io.deq.valid && reservationStations(3).io.deq.bits.uop.ctrl.fuType === FuType.mou val state = RegInit(s_normal)
// amo should always go through store issue queue 0
assert(!st1_atomics)
atomicsUnit.io.dtlb.resp.valid := false.B val atomic_rs0 = exuParameters.LduCnt + 0
atomicsUnit.io.dtlb.resp.bits := DontCare val atomic_rs1 = exuParameters.LduCnt + 1
atomicsUnit.io.dtlb.req.ready := dtlb.io.requestor(0).req.ready val st0_atomics = reservationStations(atomic_rs0).io.deq.valid && reservationStations(atomic_rs0).io.deq.bits.uop.ctrl.fuType === FuType.mou
val st1_atomics = reservationStations(atomic_rs1).io.deq.valid && reservationStations(atomic_rs1).io.deq.bits.uop.ctrl.fuType === FuType.mou
// dispatch 0 takes priority
atomicsUnit.io.in.valid := st0_atomics
atomicsUnit.io.in.bits := reservationStations(2).io.deq.bits
when (st0_atomics) { when (st0_atomics) {
reservationStations(0).io.deq.ready := atomicsUnit.io.in.ready reservationStations(atomic_rs0).io.deq.ready := atomicsUnit.io.in.ready
storeUnits(0).io.stin.valid := false.B storeUnits(0).io.stin.valid := false.B
}
when(atomicsUnit.io.dtlb.req.valid) { state := s_atomics_0
dtlb.io.requestor(0) <> atomicsUnit.io.dtlb assert(!st1_atomics)
// take load unit 0's tlb port
// make sure not to disturb loadUnit
assert(!loadUnits(0).io.dtlb.req.valid)
loadUnits(0).io.dtlb.resp.valid := false.B
} }
when (st1_atomics) {
reservationStations(atomic_rs1).io.deq.ready := atomicsUnit.io.in.ready
storeUnits(1).io.stin.valid := false.B
when(atomicsUnit.io.tlbFeedback.valid) { state := s_atomics_1
assert(!storeUnits(0).io.tlbFeedback.valid) assert(!st0_atomics)
atomicsUnit.io.tlbFeedback <> reservationStations(exuParameters.LduCnt + 0).io.feedback
} }
when (atomicsUnit.io.out.valid) {
assert(state === s_atomics_0 || state === s_atomics_1)
state := s_normal
}
atomicsUnit.io.in.valid := st0_atomics || st1_atomics
atomicsUnit.io.in.bits := Mux(st0_atomics, reservationStations(atomic_rs0).io.deq.bits, reservationStations(atomic_rs1).io.deq.bits)
atomicsUnit.io.redirect <> io.fromCtrlBlock.redirect
atomicsUnit.io.dtlb.resp.valid := false.B
atomicsUnit.io.dtlb.resp.bits := DontCare
atomicsUnit.io.dtlb.req.ready := dtlb.io.requestor(0).req.ready
atomicsUnit.io.dcache <> io.dcache.atomics atomicsUnit.io.dcache <> io.dcache.atomics
atomicsUnit.io.flush_sbuffer.empty := sbuffer.io.flush.empty atomicsUnit.io.flush_sbuffer.empty := sbuffer.io.flush.empty
atomicsUnit.io.redirect <> io.fromCtrlBlock.redirect // for atomicsUnit, it uses loadUnit(0)'s TLB port
when (state === s_atomics_0 || state === s_atomics_1) {
atomicsUnit.io.dtlb <> dtlb.io.requestor(0)
when(atomicsUnit.io.out.valid){ loadUnits(0).io.dtlb.resp.valid := false.B
// take load unit 0's write back port
assert(!loadUnits(0).io.ldout.valid)
loadUnits(0).io.ldout.ready := false.B loadUnits(0).io.ldout.ready := false.B
// make sure there's no in-flight uops in load unit
assert(!loadUnits(0).io.dtlb.req.valid)
assert(!loadUnits(0).io.ldout.valid)
}
when (state === s_atomics_0) {
atomicsUnit.io.tlbFeedback <> reservationStations(atomic_rs0).io.feedback
assert(!storeUnits(0).io.tlbFeedback.valid)
}
when (state === s_atomics_1) {
atomicsUnit.io.tlbFeedback <> reservationStations(atomic_rs1).io.feedback
assert(!storeUnits(1).io.tlbFeedback.valid)
} }
lsq.io.exceptionAddr.lsIdx := io.lsqio.exceptionAddr.lsIdx lsq.io.exceptionAddr.lsIdx := io.lsqio.exceptionAddr.lsIdx
......
...@@ -7,7 +7,7 @@ import utils._ ...@@ -7,7 +7,7 @@ import utils._
import chisel3.ExcitingUtils._ import chisel3.ExcitingUtils._
class BrqPtr extends CircularQueuePtr(BrqPtr.BrqSize) { class BrqPtr extends CircularQueuePtr(BrqPtr.BrqSize) with HasCircularQueuePtrHelper {
// this.age < that.age // this.age < that.age
final def < (that: BrqPtr): Bool = { final def < (that: BrqPtr): Bool = {
...@@ -17,10 +17,12 @@ class BrqPtr extends CircularQueuePtr(BrqPtr.BrqSize) { ...@@ -17,10 +17,12 @@ class BrqPtr extends CircularQueuePtr(BrqPtr.BrqSize) {
) )
} }
def needBrFlush(redirectTag: BrqPtr): Bool = this < redirectTag def needBrFlush(redirect: Valid[Redirect]): Bool = {
isAfter(this, redirect.bits.brTag) || (redirect.bits.flushItself() && redirect.bits.brTag === this)
}
def needFlush(redirect: Valid[Redirect]): Bool = { def needFlush(redirect: Valid[Redirect]): Bool = {
redirect.valid && (redirect.bits.isException || redirect.bits.isFlushPipe || needBrFlush(redirect.bits.brTag)) //TODO: discuss if (isException || isFlushPipe) need here? redirect.bits.isUnconditional() || needBrFlush(redirect)
} }
override def toPrintable: Printable = p"f:$flag v:$value" override def toPrintable: Printable = p"f:$flag v:$value"
...@@ -37,12 +39,9 @@ object BrqPtr extends HasXSParameter { ...@@ -37,12 +39,9 @@ object BrqPtr extends HasXSParameter {
} }
class BrqIO extends XSBundle{ class BrqIO extends XSBundle{
// interrupt/exception happen, flush Brq val redirect = Input(ValidIO(new Redirect))
val roqRedirect = Input(Valid(new Redirect))
// mem replay
val memRedirect = Input(Valid(new Redirect))
// receive branch/jump calculated target // receive branch/jump calculated target
val exuRedirect = Vec(exuParameters.AluCnt + exuParameters.JmpCnt, Flipped(ValidIO(new ExuOutput))) val exuRedirectWb = Vec(exuParameters.AluCnt + exuParameters.JmpCnt, Flipped(ValidIO(new ExuOutput)))
// from decode, branch insts enq // from decode, branch insts enq
val enqReqs = Vec(DecodeWidth, Flipped(DecoupledIO(new CfCtrl))) val enqReqs = Vec(DecodeWidth, Flipped(DecoupledIO(new CfCtrl)))
// to decode // to decode
...@@ -50,12 +49,10 @@ class BrqIO extends XSBundle{ ...@@ -50,12 +49,10 @@ class BrqIO extends XSBundle{
// to roq // to roq
val out = ValidIO(new ExuOutput) val out = ValidIO(new ExuOutput)
// misprediction, flush pipeline // misprediction, flush pipeline
val redirect = Output(Valid(new Redirect)) val redirectOut = Output(Valid(new Redirect))
val outOfOrderBrInfo = ValidIO(new BranchUpdateInfo) val cfiInfo = ValidIO(new CfiUpdateInfo)
// commit cnt of branch instr // commit cnt of branch instr
val bcommit = Input(UInt(BrTagWidth.W)) val bcommit = Input(UInt(BrTagWidth.W))
// in order dequeue to train bpd
val inOrderBrInfo = ValidIO(new BranchUpdateInfo)
} }
class Brq extends XSModule with HasCircularQueuePtrHelper { class Brq extends XSModule with HasCircularQueuePtrHelper {
...@@ -63,172 +60,135 @@ class Brq extends XSModule with HasCircularQueuePtrHelper { ...@@ -63,172 +60,135 @@ class Brq extends XSModule with HasCircularQueuePtrHelper {
class BrqEntry extends Bundle { class BrqEntry extends Bundle {
val ptrFlag = Bool() val ptrFlag = Bool()
val npc = UInt(VAddrBits.W)
val exuOut = new ExuOutput val exuOut = new ExuOutput
} }
val s_invalid :: s_idle :: s_wb :: s_commited :: Nil = val s_idle :: s_wb :: Nil = Enum(2)
List.tabulate(4)(i => (1 << i).U(4.W).asTypeOf(new StateQueueEntry))
class StateQueueEntry extends Bundle{
val isCommit = Bool()
val isWb = Bool()
val isIdle = Bool()
val isInvalid = Bool()
}
val brCommitCnt = RegInit(0.U(BrTagWidth.W)) // data and state
val brQueue = Mem(BrqSize, new BrqEntry) //Reg(Vec(BrqSize, new BrqEntry)) val brQueue = Mem(BrqSize, new BrqEntry) //Reg(Vec(BrqSize, new BrqEntry))
val stateQueue = RegInit(VecInit(Seq.fill(BrqSize)(s_invalid))) val stateQueue = RegInit(VecInit(Seq.fill(BrqSize)(s_idle)))
// queue pointers
val headPtr, tailPtr = RegInit(BrqPtr(false.B, 0.U)) val headPtr, tailPtr = RegInit(BrqPtr(false.B, 0.U))
val writebackPtr = RegInit(BrqPtr(false.B, 0.U))
// dequeue
val headIdx = headPtr.value val headIdx = headPtr.value
val writebackIdx = writebackPtr.value
val skipMask = Cat(stateQueue.map(_.isCommit).reverse)
/**
/* * commit (dequeue): after ROB commits branch instructions, move headPtr forward
example: headIdx = 2 */
headIdxMaskHi = 11111100 headPtr := headPtr + io.bcommit
headIdxMaskLo = 00000011
commitIdxHi = 6 /**
commitIdxLo = 0 * write back
commitIdx = 6 */
*/ val wbValid = stateQueue(writebackIdx) === s_wb
val headIdxMaskLo = UIntToMask(headIdx, BrqSize) val wbEntry = brQueue(writebackIdx)
val headIdxMaskHi = ~headIdxMaskLo val wbIsMisPred = wbEntry.exuOut.redirect.target =/= wbEntry.exuOut.brUpdate.pnpc
val commitIdxHi = PriorityEncoder((~skipMask).asUInt() & headIdxMaskHi) io.redirectOut.valid := wbValid && wbIsMisPred
val (commitIdxLo, findLo) = PriorityEncoderWithFlag((~skipMask).asUInt() & headIdxMaskLo) io.redirectOut.bits := wbEntry.exuOut.redirect
io.redirectOut.bits.brTag := BrqPtr(wbEntry.ptrFlag, writebackIdx)
val skipHi = (skipMask | headIdxMaskLo) === Fill(BrqSize, 1.U(1.W))
val useLo = skipHi && findLo io.out.valid := wbValid
io.out.bits := wbEntry.exuOut
when (wbValid) {
val commitIdx = Mux(stateQueue(commitIdxHi).isWb, stateQueue(writebackIdx) := s_idle
commitIdxHi, writebackPtr := writebackPtr + 1.U
Mux(useLo && stateQueue(commitIdxLo).isWb,
commitIdxLo,
headIdx
)
)
val deqValid = stateQueue(headIdx).isCommit && brCommitCnt=/=0.U
val commitValid = stateQueue(commitIdx).isWb
val commitEntry = brQueue(commitIdx)
val commitIsMisPred = commitEntry.exuOut.redirect.isMisPred
brCommitCnt := brCommitCnt + io.bcommit - deqValid
XSDebug(p"brCommitCnt:$brCommitCnt\n")
assert(brCommitCnt+io.bcommit >= deqValid)
io.inOrderBrInfo.valid := commitValid
io.inOrderBrInfo.bits := commitEntry.exuOut.brUpdate
XSDebug(io.inOrderBrInfo.valid, "inOrderValid: pc=%x\n", io.inOrderBrInfo.bits.pc)
XSDebug(p"headIdx:$headIdx commitIdx:$commitIdx\n")
XSDebug(p"headPtr:$headPtr tailPtr:$tailPtr\n")
XSDebug("")
stateQueue.reverse.map(s =>{
XSDebug(false, s.isInvalid, "-")
XSDebug(false, s.isIdle, "i")
XSDebug(false, s.isWb, "w")
XSDebug(false, s.isCommit, "c")
})
XSDebug(false, true.B, "\n")
val headPtrNext = WireInit(headPtr + deqValid)
when(commitValid){
stateQueue(commitIdx) := s_commited
}
when(deqValid){
stateQueue(headIdx) := s_invalid
} }
assert(!(commitIdx===headIdx && commitValid && deqValid), "Error: deq and commit a same entry!")
headPtr := headPtrNext val brTagRead = RegNext(Mux(io.redirect.bits.flushItself(), io.redirect.bits.brTag - 1.U, io.redirect.bits.brTag))
io.redirect.valid := commitValid && io.cfiInfo.valid := RegNext(io.redirect.valid || wbValid)
commitIsMisPred //&& io.cfiInfo.bits := brQueue(brTagRead.value).exuOut.brUpdate
// !io.roqRedirect.valid && io.cfiInfo.bits.brTag := brTagRead
// !io.redirect.bits.roqIdx.needFlush(io.memRedirect) io.cfiInfo.bits.isReplay := RegNext(io.redirect.bits.flushItself())
io.cfiInfo.bits.isMisPred := RegNext(wbIsMisPred)
io.redirect.bits := commitEntry.exuOut.redirect
io.out.valid := commitValid
io.out.bits := commitEntry.exuOut
io.outOfOrderBrInfo.valid := commitValid
io.outOfOrderBrInfo.bits := commitEntry.exuOut.brUpdate
when (io.redirect.valid) {
commitEntry.npc := io.redirect.bits.target
}
XSInfo(io.out.valid, XSInfo(io.out.valid,
p"commit branch to roq, mispred:${io.redirect.valid} pc=${Hexadecimal(io.out.bits.uop.cf.pc)}\n" p"commit branch to roq, mispred:${io.redirectOut.valid} pc=${Hexadecimal(io.out.bits.uop.cf.pc)}\n"
) )
// branch insts enq /**
* branch insts enq
*/
// note that redirect sent to IFU is delayed for one clock cycle
// thus, brq should not allow enqueue in the next cycle after redirect
val lastCycleRedirect = RegNext(io.redirect.valid)
val validEntries = distanceBetween(tailPtr, headPtr) val validEntries = distanceBetween(tailPtr, headPtr)
for(i <- 0 until DecodeWidth){ for(i <- 0 until DecodeWidth){
val offset = if(i == 0) 0.U else PopCount(io.enqReqs.take(i).map(_.valid)) val offset = if(i == 0) 0.U else PopCount(io.enqReqs.take(i).map(_.valid))
val brTag = tailPtr + offset val brTag = tailPtr + offset
val idx = brTag.value val idx = brTag.value
io.enqReqs(i).ready := validEntries <= (BrqSize - (i + 1)).U io.enqReqs(i).ready := validEntries <= (BrqSize - (i + 1)).U && !lastCycleRedirect
io.brTags(i) := brTag io.brTags(i) := brTag
when(io.enqReqs(i).fire()){ when (io.enqReqs(i).fire()) {
brQueue(idx).npc := io.enqReqs(i).bits.cf.brUpdate.pnpc
brQueue(idx).ptrFlag := brTag.flag brQueue(idx).ptrFlag := brTag.flag
brQueue(idx).exuOut.brUpdate.pc := io.enqReqs(i).bits.cf.pc
brQueue(idx).exuOut.brUpdate.pnpc := io.enqReqs(i).bits.cf.brUpdate.pnpc
brQueue(idx).exuOut.brUpdate.fetchIdx := io.enqReqs(i).bits.cf.brUpdate.fetchIdx
brQueue(idx).exuOut.brUpdate.pd := io.enqReqs(i).bits.cf.brUpdate.pd
brQueue(idx).exuOut.brUpdate.bpuMeta := io.enqReqs(i).bits.cf.brUpdate.bpuMeta
stateQueue(idx) := s_idle stateQueue(idx) := s_idle
} }
} }
val enqCnt = PopCount(io.enqReqs.map(_.fire())) val enqCnt = PopCount(io.enqReqs.map(_.fire()))
tailPtr := tailPtr + enqCnt tailPtr := tailPtr + enqCnt
// exu write back /**
for(exuWb <- io.exuRedirect){ * exu write back
when(exuWb.valid){ */
for (exuWb <- io.exuRedirectWb) {
when (exuWb.valid) {
val wbIdx = exuWb.bits.redirect.brTag.value val wbIdx = exuWb.bits.redirect.brTag.value
XSInfo( XSInfo(
p"exu write back: brTag:${exuWb.bits.redirect.brTag}" + p"exu write back: brTag:${exuWb.bits.redirect.brTag}" +
p" pc=${Hexadecimal(exuWb.bits.uop.cf.pc)} pnpc=${Hexadecimal(brQueue(wbIdx).npc)} target=${Hexadecimal(exuWb.bits.redirect.target)}\n" p" pc=${Hexadecimal(exuWb.bits.uop.cf.pc)} " +
p"pnpc=${Hexadecimal(brQueue(wbIdx).exuOut.brUpdate.pnpc)} " +
p"target=${Hexadecimal(exuWb.bits.redirect.target)}\n"
) )
when(stateQueue(wbIdx).isIdle){ assert(stateQueue(wbIdx) === s_idle)
stateQueue(wbIdx) := s_wb stateQueue(wbIdx) := s_wb
} // only writeback necessary information
val exuOut = WireInit(exuWb.bits) brQueue(wbIdx).exuOut.uop := exuWb.bits.uop
val isMisPred = brQueue(wbIdx).npc =/= exuWb.bits.redirect.target brQueue(wbIdx).exuOut.data := exuWb.bits.data
exuOut.redirect.isMisPred := isMisPred brQueue(wbIdx).exuOut.fflags := exuWb.bits.fflags
exuOut.brUpdate.isMisPred := isMisPred brQueue(wbIdx).exuOut.redirectValid := exuWb.bits.redirectValid
brQueue(wbIdx).exuOut := exuOut brQueue(wbIdx).exuOut.redirect := exuWb.bits.redirect
brQueue(wbIdx).exuOut.debug := exuWb.bits.debug
brQueue(wbIdx).exuOut.brUpdate.target := exuWb.bits.brUpdate.target
brQueue(wbIdx).exuOut.brUpdate.brTarget := exuWb.bits.brUpdate.brTarget
brQueue(wbIdx).exuOut.brUpdate.taken := exuWb.bits.brUpdate.taken
} }
} }
when(io.roqRedirect.valid){ // when redirect is valid, we need to update the states and pointers
// exception when (io.redirect.valid) {
stateQueue.foreach(_ := s_invalid) // For unconditional redirect, flush all entries
headPtr := BrqPtr(false.B, 0.U) when (io.redirect.bits.isUnconditional()) {
tailPtr := BrqPtr(false.B, 0.U) stateQueue.foreach(_ := s_idle)
brCommitCnt := 0.U headPtr := BrqPtr(false.B, 0.U)
}.elsewhen(io.memRedirect.valid){ tailPtr := BrqPtr(false.B, 0.U)
// misprediction or replay writebackPtr := BrqPtr(false.B, 0.U)
stateQueue.zipWithIndex.foreach({case(s, i) => }.otherwise {
// replay should flush brTag // conditional check: branch mis-prediction and memory dependence violation
val ptr = BrqPtr(brQueue(i).ptrFlag, i.U) stateQueue.zipWithIndex.foreach({ case(s, i) =>
val replayMatch = io.memRedirect.bits.isReplay && ptr === io.memRedirect.bits.brTag val ptr = BrqPtr(brQueue(i).ptrFlag, i.U)
when(io.memRedirect.valid && (ptr.needBrFlush(io.memRedirect.bits.brTag) || replayMatch)){ when (ptr.needBrFlush(io.redirect)) {
s := s_invalid s := s_idle
}
})
tailPtr := io.redirect.bits.brTag + Mux(io.redirect.bits.flushItself(), 0.U, 1.U)
when (io.redirect.bits.flushItself() && writebackPtr.needBrFlush(io.redirect)) {
writebackPtr := io.redirect.bits.brTag
} }
})
when(io.memRedirect.valid){
tailPtr := io.memRedirect.bits.brTag + Mux(io.memRedirect.bits.isReplay, 0.U, 1.U)
} }
} }
// Debug info // Debug info
val debug_roq_redirect = io.roqRedirect.valid val debug_roq_redirect = io.redirect.valid && io.redirect.bits.isUnconditional()
val debug_brq_redirect = io.redirect.valid && !debug_roq_redirect val debug_brq_redirect = io.redirectOut.valid
val debug_normal_mode = !(debug_roq_redirect || debug_brq_redirect) val debug_normal_mode = !(debug_roq_redirect || debug_brq_redirect)
for(i <- 0 until DecodeWidth){ for(i <- 0 until DecodeWidth){
...@@ -240,20 +200,29 @@ class Brq extends XSModule with HasCircularQueuePtrHelper { ...@@ -240,20 +200,29 @@ class Brq extends XSModule with HasCircularQueuePtrHelper {
} }
XSInfo(debug_roq_redirect, "roq redirect, flush brq\n") XSInfo(debug_roq_redirect, "roq redirect, flush brq\n")
XSInfo(debug_brq_redirect, p"brq redirect, target:${Hexadecimal(io.redirectOut.bits.target)}\n")
XSDebug(io.cfiInfo.valid, "inOrderValid: pc=%x\n", io.cfiInfo.bits.pc)
XSInfo(debug_brq_redirect, p"brq redirect, target:${Hexadecimal(io.redirect.bits.target)}\n") XSDebug(p"headIdx:$headIdx writebackIdx:$writebackIdx\n")
XSDebug(p"headPtr:$headPtr tailPtr:$tailPtr\n")
XSDebug("")
stateQueue.reverse.map(s =>{
XSDebug(false, s === s_idle, "-")
XSDebug(false, s === s_wb, "w")
})
XSDebug(false, true.B, "\n")
val fire = io.out.fire() val fire = io.out.fire()
val predRight = fire && !commitIsMisPred val predRight = fire && !wbIsMisPred
val predWrong = fire && commitIsMisPred val predWrong = fire && wbIsMisPred
// val isBType = commitEntry.exuOut.brUpdate.btbType===BTBtype.B // val isBType = wbEntry.exuOut.brUpdate.btbType===BTBtype.B
val isBType = commitEntry.exuOut.brUpdate.pd.isBr val isBType = wbEntry.exuOut.brUpdate.pd.isBr
// val isJType = commitEntry.exuOut.brUpdate.btbType===BTBtype.J // val isJType = wbEntry.exuOut.brUpdate.btbType===BTBtype.J
val isJType = commitEntry.exuOut.brUpdate.pd.isJal val isJType = wbEntry.exuOut.brUpdate.pd.isJal
// val isIType = commitEntry.exuOut.brUpdate.btbType===BTBtype.I // val isIType = wbEntry.exuOut.brUpdate.btbType===BTBtype.I
val isIType = commitEntry.exuOut.brUpdate.pd.isJalr val isIType = wbEntry.exuOut.brUpdate.pd.isJalr
// val isRType = commitEntry.exuOut.brUpdate.btbType===BTBtype.R // val isRType = wbEntry.exuOut.brUpdate.btbType===BTBtype.R
val isRType = commitEntry.exuOut.brUpdate.pd.isRet val isRType = wbEntry.exuOut.brUpdate.pd.isRet
val mbpInstr = fire val mbpInstr = fire
val mbpRight = predRight val mbpRight = predRight
val mbpWrong = predWrong val mbpWrong = predWrong
......
package xiangshan.backend.decode
import chisel3._
import chisel3.util._
import xiangshan._
import utils._
class DecodeBuffer extends XSModule {
val io = IO(new Bundle() {
val isWalking = Input(Bool())
val redirect = Flipped(ValidIO(new Redirect))
val in = Vec(DecodeWidth, Flipped(DecoupledIO(new CfCtrl)))
val out = Vec(RenameWidth, DecoupledIO(new CfCtrl))
})
require(DecodeWidth == RenameWidth)
val validVec = RegInit(VecInit(Seq.fill(DecodeWidth)(false.B)))
val leftCanIn = ParallelAND(
validVec.zip(io.out.map(_.fire())).map({
case (v, fire) =>
!v || fire
})
)
val flush = io.redirect.valid// && !io.redirect.bits.isReplay
for( i <- 0 until RenameWidth){
when(io.out(i).fire()){
validVec(i) := false.B
}
when(io.in(i).fire()){
validVec(i) := true.B
}
when(flush){
validVec(i) := false.B
}
val r = RegEnable(io.in(i).bits, io.in(i).fire())
io.in(i).ready := leftCanIn
io.out(i).bits <> r
io.out(i).valid := validVec(i) && !flush && !io.isWalking
}
for(in <- io.in){
XSInfo(p"in v:${in.valid} r:${in.ready} pc=${Hexadecimal(in.bits.cf.pc)}\n")
}
for(out <- io.out){
XSInfo(p"out v:${out.valid} r:${out.ready} pc=${Hexadecimal(out.bits.cf.pc)}\n")
}
}
package xiangshan.backend.decode package xiangshan.backend.decode
import chisel3._ import chisel3._
import chisel3.util.BitPat
import xiangshan.{FuType, HasXSParameter} import xiangshan.{FuType, HasXSParameter}
import xiangshan.backend._ import xiangshan.backend._
import xiangshan.backend.decode.isa._ import xiangshan.backend.decode.isa._
...@@ -32,15 +33,6 @@ trait HasInstrType { ...@@ -32,15 +33,6 @@ trait HasInstrType {
).map(_===instrType).reduce(_||_) ).map(_===instrType).reduce(_||_)
} }
object SrcType {
def reg = "b00".U
def pc = "b01".U
def imm = "b01".U
def fp = "b10".U
def apply() = UInt(2.W)
}
object FuOpType { object FuOpType {
def apply() = UInt(6.W) def apply() = UInt(6.W)
} }
......
...@@ -19,7 +19,7 @@ class DecodeStage extends XSModule { ...@@ -19,7 +19,7 @@ class DecodeStage extends XSModule {
// to DecBuffer // to DecBuffer
val out = Vec(DecodeWidth, DecoupledIO(new CfCtrl)) val out = Vec(DecodeWidth, DecoupledIO(new CfCtrl))
}) })
val decoders = Seq.fill(DecodeWidth)(Module(new Decoder)) val decoders = Seq.fill(DecodeWidth)(Module(new DecodeUnit))
val decoderToBrq = Wire(Vec(DecodeWidth, new CfCtrl)) // without brTag and brMask val decoderToBrq = Wire(Vec(DecodeWidth, new CfCtrl)) // without brTag and brMask
val decoderToDecBuffer = Wire(Vec(DecodeWidth, new CfCtrl)) // with brTag and brMask val decoderToDecBuffer = Wire(Vec(DecodeWidth, new CfCtrl)) // with brTag and brMask
...@@ -32,18 +32,18 @@ class DecodeStage extends XSModule { ...@@ -32,18 +32,18 @@ class DecodeStage extends XSModule {
// Second, assert out(i).valid iff in(i).valid and instruction is valid (not implemented) and toBrq(i).ready // Second, assert out(i).valid iff in(i).valid and instruction is valid (not implemented) and toBrq(i).ready
for (i <- 0 until DecodeWidth) { for (i <- 0 until DecodeWidth) {
decoders(i).io.in <> io.in(i).bits decoders(i).io.enq.ctrl_flow <> io.in(i).bits
decoderToBrq(i) := decoders(i).io.out // CfCtrl without bfTag and brMask decoderToBrq(i) := decoders(i).io.deq.cf_ctrl // CfCtrl without bfTag and brMask
decoderToBrq(i).brTag := DontCare decoderToBrq(i).brTag := DontCare
io.toBrq(i).bits := decoderToBrq(i) io.toBrq(i).bits := decoderToBrq(i)
decoderToDecBuffer(i) := decoders(i).io.out decoderToDecBuffer(i) := decoders(i).io.deq.cf_ctrl
decoderToDecBuffer(i).brTag := io.brTags(i) decoderToDecBuffer(i).brTag := io.brTags(i)
io.out(i).bits := decoderToDecBuffer(i) io.out(i).bits := decoderToDecBuffer(i)
val isMret = decoders(i).io.out.cf.instr === BitPat("b001100000010_00000_000_00000_1110011") val isMret = decoders(i).io.deq.cf_ctrl.cf.instr === BitPat("b001100000010_00000_000_00000_1110011")
val isSret = decoders(i).io.out.cf.instr === BitPat("b000100000010_00000_000_00000_1110011") val isSret = decoders(i).io.deq.cf_ctrl.cf.instr === BitPat("b000100000010_00000_000_00000_1110011")
val thisBrqValid = !decoders(i).io.out.cf.brUpdate.pd.notCFI || isMret || isSret val thisBrqValid = !decoders(i).io.deq.cf_ctrl.cf.brUpdate.pd.notCFI || isMret || isSret
io.in(i).ready := io.out(i).ready && io.toBrq(i).ready io.in(i).ready := io.out(i).ready && io.toBrq(i).ready
io.out(i).valid := io.in(i).valid && io.toBrq(i).ready io.out(i).valid := io.in(i).valid && io.toBrq(i).ready
io.toBrq(i).valid := io.in(i).valid && thisBrqValid && io.out(i).ready io.toBrq(i).valid := io.in(i).valid && thisBrqValid && io.out(i).ready
......
...@@ -6,12 +6,12 @@ import xiangshan._ ...@@ -6,12 +6,12 @@ import xiangshan._
import utils._ import utils._
import xiangshan.backend.regfile.RfReadPort import xiangshan.backend.regfile.RfReadPort
import chisel3.ExcitingUtils._ import chisel3.ExcitingUtils._
import xiangshan.backend.roq.RoqPtr import xiangshan.backend.roq.{RoqPtr, RoqEnqIO}
import xiangshan.backend.rename.RenameBypassInfo import xiangshan.backend.rename.RenameBypassInfo
import xiangshan.mem.LsqEnqIO
case class DispatchParameters case class DispatchParameters
( (
DqEnqWidth: Int,
IntDqSize: Int, IntDqSize: Int,
FpDqSize: Int, FpDqSize: Int,
LsDqSize: Int, LsDqSize: Int,
...@@ -30,19 +30,9 @@ class Dispatch extends XSModule { ...@@ -30,19 +30,9 @@ class Dispatch extends XSModule {
// to busytable: set pdest to busy (not ready) when they are dispatched // to busytable: set pdest to busy (not ready) when they are dispatched
val allocPregs = Vec(RenameWidth, Output(new ReplayPregReq)) val allocPregs = Vec(RenameWidth, Output(new ReplayPregReq))
// enq Roq // enq Roq
val enqRoq = new Bundle { val enqRoq = Flipped(new RoqEnqIO)
val canAccept = Input(Bool())
val isEmpty = Input(Bool())
val extraWalk = Vec(RenameWidth, Output(Bool()))
val req = Vec(RenameWidth, ValidIO(new MicroOp))
val resp = Vec(RenameWidth, Input(new RoqPtr))
}
// enq Lsq // enq Lsq
val enqLsq = new Bundle() { val enqLsq = Flipped(new LsqEnqIO)
val canAccept = Input(Bool())
val req = Vec(RenameWidth, ValidIO(new MicroOp))
val resp = Vec(RenameWidth, Input(new LSIdx))
}
// read regfile // read regfile
val readIntRf = Vec(NRIntReadPorts, Flipped(new RfReadPort)) val readIntRf = Vec(NRIntReadPorts, Flipped(new RfReadPort))
val readFpRf = Vec(NRFpReadPorts, Flipped(new RfReadPort)) val readFpRf = Vec(NRFpReadPorts, Flipped(new RfReadPort))
...@@ -56,9 +46,9 @@ class Dispatch extends XSModule { ...@@ -56,9 +46,9 @@ class Dispatch extends XSModule {
}) })
val dispatch1 = Module(new Dispatch1) val dispatch1 = Module(new Dispatch1)
val intDq = Module(new DispatchQueue(dpParams.IntDqSize, dpParams.DqEnqWidth, dpParams.IntDqDeqWidth)) val intDq = Module(new DispatchQueue(dpParams.IntDqSize, RenameWidth, dpParams.IntDqDeqWidth))
val fpDq = Module(new DispatchQueue(dpParams.FpDqSize, dpParams.DqEnqWidth, dpParams.FpDqDeqWidth)) val fpDq = Module(new DispatchQueue(dpParams.FpDqSize, RenameWidth, dpParams.FpDqDeqWidth))
val lsDq = Module(new DispatchQueue(dpParams.LsDqSize, dpParams.DqEnqWidth, dpParams.LsDqDeqWidth)) val lsDq = Module(new DispatchQueue(dpParams.LsDqSize, RenameWidth, dpParams.LsDqDeqWidth))
// pipeline between rename and dispatch // pipeline between rename and dispatch
// accepts all at once // accepts all at once
...@@ -68,15 +58,12 @@ class Dispatch extends XSModule { ...@@ -68,15 +58,12 @@ class Dispatch extends XSModule {
} }
// dispatch 1: accept uops from rename and dispatch them to the three dispatch queues // dispatch 1: accept uops from rename and dispatch them to the three dispatch queues
dispatch1.io.redirect <> io.redirect // dispatch1.io.redirect <> io.redirect
dispatch1.io.renameBypass := RegEnable(io.renameBypass, io.fromRename(0).valid && dispatch1.io.fromRename(0).ready) dispatch1.io.renameBypass := RegEnable(io.renameBypass, io.fromRename(0).valid && dispatch1.io.fromRename(0).ready)
dispatch1.io.enqRoq <> io.enqRoq dispatch1.io.enqRoq <> io.enqRoq
dispatch1.io.enqLsq <> io.enqLsq dispatch1.io.enqLsq <> io.enqLsq
dispatch1.io.toIntDqReady <> intDq.io.enqReady
dispatch1.io.toIntDq <> intDq.io.enq dispatch1.io.toIntDq <> intDq.io.enq
dispatch1.io.toFpDqReady <> fpDq.io.enqReady
dispatch1.io.toFpDq <> fpDq.io.enq dispatch1.io.toFpDq <> fpDq.io.enq
dispatch1.io.toLsDqReady <> lsDq.io.enqReady
dispatch1.io.toLsDq <> lsDq.io.enq dispatch1.io.toLsDq <> lsDq.io.enq
dispatch1.io.allocPregs <> io.allocPregs dispatch1.io.allocPregs <> io.allocPregs
......
...@@ -5,40 +5,35 @@ import chisel3.util._ ...@@ -5,40 +5,35 @@ import chisel3.util._
import chisel3.ExcitingUtils._ import chisel3.ExcitingUtils._
import xiangshan._ import xiangshan._
import utils._ import utils._
import xiangshan.backend.roq.RoqPtr import xiangshan.backend.roq.{RoqPtr, RoqEnqIO}
import xiangshan.backend.rename.RenameBypassInfo import xiangshan.backend.rename.RenameBypassInfo
import xiangshan.mem.LsqEnqIO
// read rob and enqueue // read rob and enqueue
class Dispatch1 extends XSModule { class Dispatch1 extends XSModule {
val io = IO(new Bundle() { val io = IO(new Bundle() {
val redirect = Flipped(ValidIO(new Redirect))
// from rename // from rename
val fromRename = Vec(RenameWidth, Flipped(DecoupledIO(new MicroOp))) val fromRename = Vec(RenameWidth, Flipped(DecoupledIO(new MicroOp)))
val renameBypass = Input(new RenameBypassInfo) val renameBypass = Input(new RenameBypassInfo)
val recv = Output(Vec(RenameWidth, Bool())) val recv = Output(Vec(RenameWidth, Bool()))
// enq Roq // enq Roq
val enqRoq = new Bundle { val enqRoq = Flipped(new RoqEnqIO)
// enq Lsq
val enqLsq = Flipped(new LsqEnqIO)
val allocPregs = Vec(RenameWidth, Output(new ReplayPregReq))
// to dispatch queue
val toIntDq = new Bundle {
val canAccept = Input(Bool()) val canAccept = Input(Bool())
val isEmpty = Input(Bool())
// if set, Roq needs extra walk
val extraWalk = Vec(RenameWidth, Output(Bool()))
val req = Vec(RenameWidth, ValidIO(new MicroOp)) val req = Vec(RenameWidth, ValidIO(new MicroOp))
val resp = Vec(RenameWidth, Input(new RoqPtr))
} }
// enq Lsq val toFpDq = new Bundle {
val enqLsq = new Bundle() { val canAccept = Input(Bool())
val req = Vec(RenameWidth, ValidIO(new MicroOp))
}
val toLsDq = new Bundle {
val canAccept = Input(Bool()) val canAccept = Input(Bool())
val req = Vec(RenameWidth, ValidIO(new MicroOp)) val req = Vec(RenameWidth, ValidIO(new MicroOp))
val resp = Vec(RenameWidth, Input(new LSIdx))
} }
val allocPregs = Vec(RenameWidth, Output(new ReplayPregReq))
// to dispatch queue
val toIntDqReady = Input(Bool())
val toIntDq = Vec(dpParams.DqEnqWidth, ValidIO(new MicroOp))
val toFpDqReady = Input(Bool())
val toFpDq = Vec(dpParams.DqEnqWidth, ValidIO(new MicroOp))
val toLsDqReady = Input(Bool())
val toLsDq = Vec(dpParams.DqEnqWidth, ValidIO(new MicroOp))
}) })
...@@ -46,29 +41,18 @@ class Dispatch1 extends XSModule { ...@@ -46,29 +41,18 @@ class Dispatch1 extends XSModule {
* Part 1: choose the target dispatch queue and the corresponding write ports * Part 1: choose the target dispatch queue and the corresponding write ports
*/ */
// valid bits for different dispatch queues // valid bits for different dispatch queues
val isInt = VecInit(io.fromRename.map(req => FuType.isIntExu(req.bits.ctrl.fuType))) val isInt = VecInit(io.fromRename.map(req => FuType.isIntExu(req.bits.ctrl.fuType)))
val isFp = VecInit(io.fromRename.map(req => FuType.isFpExu (req.bits.ctrl.fuType))) val isBranch = VecInit(io.fromRename.map(req => !req.bits.cf.brUpdate.pd.notCFI))
val isLs = VecInit(io.fromRename.map(req => FuType.isMemExu(req.bits.ctrl.fuType))) val isFp = VecInit(io.fromRename.map(req => FuType.isFpExu (req.bits.ctrl.fuType)))
val isStore = VecInit(io.fromRename.map(req => FuType.isStoreExu(req.bits.ctrl.fuType))) val isLs = VecInit(io.fromRename.map(req => FuType.isMemExu(req.bits.ctrl.fuType)))
val isStore = VecInit(io.fromRename.map(req => FuType.isStoreExu(req.bits.ctrl.fuType)))
val isAMO = VecInit(io.fromRename.map(req => req.bits.ctrl.fuType === FuType.mou))
val isBlockBackward = VecInit(io.fromRename.map(_.bits.ctrl.blockBackward)) val isBlockBackward = VecInit(io.fromRename.map(_.bits.ctrl.blockBackward))
val isNoSpecExec = VecInit(io.fromRename.map(_.bits.ctrl.noSpecExec)) val isNoSpecExec = VecInit(io.fromRename.map(_.bits.ctrl.noSpecExec))
// generate index mapping
val intIndex = Module(new IndexMapping(RenameWidth, dpParams.DqEnqWidth, false))
val fpIndex = Module(new IndexMapping(RenameWidth, dpParams.DqEnqWidth, false))
val lsIndex = Module(new IndexMapping(RenameWidth, dpParams.DqEnqWidth, false))
for (i <- 0 until RenameWidth) {
intIndex.io.validBits(i) := isInt(i) && io.fromRename(i).valid
fpIndex.io.validBits(i) := isFp(i) && io.fromRename(i).valid
lsIndex.io.validBits(i) := isLs(i) && io.fromRename(i).valid
}
intIndex.io.priority := DontCare
fpIndex.io.priority := DontCare
lsIndex.io.priority := DontCare
/** /**
* Part 2: * Part 2:
* Update commitType, psrc1, psrc2, psrc3, old_pdest for the uops * Update commitType, psrc1, psrc2, psrc3, old_pdest, roqIdx, lqIdx, sqIdx for the uops
*/ */
val updatedUop = Wire(Vec(RenameWidth, new MicroOp)) val updatedUop = Wire(Vec(RenameWidth, new MicroOp))
val updatedCommitType = Wire(Vec(RenameWidth, CommitType())) val updatedCommitType = Wire(Vec(RenameWidth, CommitType()))
...@@ -78,7 +62,7 @@ class Dispatch1 extends XSModule { ...@@ -78,7 +62,7 @@ class Dispatch1 extends XSModule {
val updatedOldPdest = Wire(Vec(RenameWidth, UInt(PhyRegIdxWidth.W))) val updatedOldPdest = Wire(Vec(RenameWidth, UInt(PhyRegIdxWidth.W)))
for (i <- 0 until RenameWidth) { for (i <- 0 until RenameWidth) {
updatedCommitType(i) := Cat(isLs(i), isStore(i) | isFp(i)) updatedCommitType(i) := Cat(isLs(i) && !isAMO(i), isStore(i) | isBranch(i))
updatedPsrc1(i) := io.fromRename.take(i).map(_.bits.pdest) updatedPsrc1(i) := io.fromRename.take(i).map(_.bits.pdest)
.zip(if (i == 0) Seq() else io.renameBypass.lsrc1_bypass(i-1).asBools) .zip(if (i == 0) Seq() else io.renameBypass.lsrc1_bypass(i-1).asBools)
.foldLeft(io.fromRename(i).bits.psrc1) { .foldLeft(io.fromRename(i).bits.psrc1) {
...@@ -108,6 +92,10 @@ class Dispatch1 extends XSModule { ...@@ -108,6 +92,10 @@ class Dispatch1 extends XSModule {
updatedUop(i).old_pdest := updatedOldPdest(i) updatedUop(i).old_pdest := updatedOldPdest(i)
// update commitType // update commitType
updatedUop(i).ctrl.commitType := updatedCommitType(i) updatedUop(i).ctrl.commitType := updatedCommitType(i)
// update roqIdx, lqIdx, sqIdx
updatedUop(i).roqIdx := io.enqRoq.resp(i)
updatedUop(i).lqIdx := io.enqLsq.resp(i).lqIdx
updatedUop(i).sqIdx := io.enqLsq.resp(i).sqIdx
} }
...@@ -116,110 +104,78 @@ class Dispatch1 extends XSModule { ...@@ -116,110 +104,78 @@ class Dispatch1 extends XSModule {
* acquire ROQ (all), LSQ (load/store only) and dispatch queue slots * acquire ROQ (all), LSQ (load/store only) and dispatch queue slots
* only set valid when all of them provides enough entries * only set valid when all of them provides enough entries
*/ */
val redirectValid = io.redirect.valid// && !io.redirect.bits.isReplay val allResourceReady = io.enqLsq.canAccept && io.enqRoq.canAccept && io.toIntDq.canAccept && io.toFpDq.canAccept && io.toLsDq.canAccept
val allResourceReady = io.enqLsq.canAccept && io.enqRoq.canAccept && io.toIntDqReady && io.toFpDqReady && io.toLsDqReady
// Instructions should enter dispatch queues in order. // Instructions should enter dispatch queues in order.
// When RenameWidth > DqEnqWidth, it's possible that some instructions cannot enter dispatch queue
// because previous instructions cannot enter dispatch queue.
// The reason is that although ROB and LSQ have enough empty slots, dispatch queue has limited enqueue ports.
// Thus, for i >= dpParams.DqEnqWidth, we have to check whether it's previous instructions (and the instruction itself) can enqueue.
// However, since, for instructions with indices less than dpParams.DqEnqWidth,
// they can always enter dispatch queue when ROB and LSQ are ready, we don't need to check whether they can enqueue.
// thisIsBlocked: this instruction is blocked by itself (based on noSpecExec) // thisIsBlocked: this instruction is blocked by itself (based on noSpecExec)
// thisCanOut: this instruction can enqueue (based on resource) // nextCanOut: next instructions can out (based on blockBackward)
// nextCanOut: next instructions can out (based on blockBackward and previous instructions)
// notBlockedByPrevious: previous instructions can enqueue // notBlockedByPrevious: previous instructions can enqueue
val thisIsBlocked = VecInit((0 until RenameWidth).map(i => { val thisIsBlocked = VecInit((0 until RenameWidth).map(i => {
// for i > 0, when Roq is empty but dispatch1 have valid instructions to enqueue, it's blocked // for i > 0, when Roq is empty but dispatch1 have valid instructions to enqueue, it's blocked
if (i > 0) isNoSpecExec(i) && (!io.enqRoq.isEmpty || Cat(io.fromRename.take(i).map(_.valid)).orR) if (i > 0) isNoSpecExec(i) && (!io.enqRoq.isEmpty || Cat(io.fromRename.take(i).map(_.valid)).orR)
else isNoSpecExec(i) && !io.enqRoq.isEmpty else isNoSpecExec(i) && !io.enqRoq.isEmpty
})) }))
val thisCanOut = VecInit((0 until RenameWidth).map(i => {
// For i in [0, DqEnqWidth), they can always enqueue when ROB and LSQ are ready
if (i < dpParams.DqEnqWidth) true.B
else Cat(Seq(intIndex, fpIndex, lsIndex).map(_.io.reverseMapping(i).valid)).orR
}))
val nextCanOut = VecInit((0 until RenameWidth).map(i => val nextCanOut = VecInit((0 until RenameWidth).map(i =>
(thisCanOut(i) && !isNoSpecExec(i) && !isBlockBackward(i)) || !io.fromRename(i).valid (!isNoSpecExec(i) && !isBlockBackward(i)) || !io.fromRename(i).valid
)) ))
val notBlockedByPrevious = VecInit((0 until RenameWidth).map(i => val notBlockedByPrevious = VecInit((0 until RenameWidth).map(i =>
if (i == 0) true.B if (i == 0) true.B
else Cat((0 until i).map(j => nextCanOut(j))).andR else Cat((0 until i).map(j => nextCanOut(j))).andR
)) ))
// for noSpecExec: (roqEmpty || !this.noSpecExec) && !previous.noSpecExec
// For blockBackward:
// this instruction can actually dequeue: 3 conditions // this instruction can actually dequeue: 3 conditions
// (1) resources are ready // (1) resources are ready
// (2) previous instructions are ready // (2) previous instructions are ready
val thisCanActualOut = (0 until RenameWidth).map(i => allResourceReady && thisCanOut(i) && !thisIsBlocked(i) && notBlockedByPrevious(i)) val thisCanActualOut = (0 until RenameWidth).map(i => !thisIsBlocked(i) && notBlockedByPrevious(i))
// input for ROQ and LSQ // input for ROQ, LSQ, Dispatch Queue
// note that LSQ needs roqIdx
for (i <- 0 until RenameWidth) { for (i <- 0 until RenameWidth) {
io.enqRoq.extraWalk(i) := io.fromRename(i).valid && !thisCanActualOut(i) io.enqRoq.needAlloc(i) := io.fromRename(i).valid
io.enqRoq.req(i).valid := io.fromRename(i).valid && thisCanActualOut(i) io.enqRoq.req(i).valid := io.fromRename(i).valid && thisCanActualOut(i) && io.enqLsq.canAccept && io.toIntDq.canAccept && io.toFpDq.canAccept && io.toLsDq.canAccept
io.enqRoq.req(i).bits := updatedUop(i) io.enqRoq.req(i).bits := updatedUop(i)
XSDebug(io.enqRoq.req(i).valid, p"pc 0x${Hexadecimal(io.fromRename(i).bits.cf.pc)} receives nroq ${io.enqRoq.resp(i)}\n")
val shouldEnqLsq = isLs(i) && io.fromRename(i).bits.ctrl.fuType =/= FuType.mou val shouldEnqLsq = isLs(i) && !isAMO(i)
io.enqLsq.req(i).valid := io.fromRename(i).valid && shouldEnqLsq && !redirectValid && thisCanActualOut(i) io.enqLsq.needAlloc(i) := io.fromRename(i).valid && shouldEnqLsq
io.enqLsq.req(i).valid := io.fromRename(i).valid && shouldEnqLsq && thisCanActualOut(i) && io.enqRoq.canAccept && io.toIntDq.canAccept && io.toFpDq.canAccept && io.toLsDq.canAccept
io.enqLsq.req(i).bits := updatedUop(i) io.enqLsq.req(i).bits := updatedUop(i)
io.enqLsq.req(i).bits.roqIdx := io.enqRoq.resp(i) io.enqLsq.req(i).bits.roqIdx := io.enqRoq.resp(i)
XSDebug(io.enqLsq.req(i).valid, XSDebug(io.enqLsq.req(i).valid,
p"pc 0x${Hexadecimal(io.fromRename(i).bits.cf.pc)} receives lq ${io.enqLsq.resp(i).lqIdx} sq ${io.enqLsq.resp(i).sqIdx}\n") p"pc 0x${Hexadecimal(io.fromRename(i).bits.cf.pc)} receives lq ${io.enqLsq.resp(i).lqIdx} sq ${io.enqLsq.resp(i).sqIdx}\n")
XSDebug(io.enqRoq.req(i).valid, p"pc 0x${Hexadecimal(io.fromRename(i).bits.cf.pc)} receives nroq ${io.enqRoq.resp(i)}\n") // send uops to dispatch queues
} // Note that if one of their previous instructions cannot enqueue, they should not enter dispatch queue.
// We use notBlockedByPrevious here.
io.toIntDq.req(i).bits := updatedUop(i)
io.toIntDq.req(i).valid := io.fromRename(i).valid && isInt(i) && thisCanActualOut(i) &&
io.enqLsq.canAccept && io.enqRoq.canAccept && io.toFpDq.canAccept && io.toLsDq.canAccept
io.toFpDq.req(i).bits := updatedUop(i)
io.toFpDq.req(i).valid := io.fromRename(i).valid && isFp(i) && thisCanActualOut(i) &&
io.enqLsq.canAccept && io.enqRoq.canAccept && io.toIntDq.canAccept && io.toLsDq.canAccept
/** io.toLsDq.req(i).bits := updatedUop(i)
* Part 4: io.toLsDq.req(i).valid := io.fromRename(i).valid && isLs(i) && thisCanActualOut(i) &&
* append ROQ and LSQ indexed to uop, and send them to dispatch queue io.enqLsq.canAccept && io.enqRoq.canAccept && io.toIntDq.canAccept && io.toFpDq.canAccept
*/
val updateUopWithIndex = Wire(Vec(RenameWidth, new MicroOp))
for (i <- 0 until RenameWidth) {
updateUopWithIndex(i) := updatedUop(i)
updateUopWithIndex(i).roqIdx := io.enqRoq.resp(i)
updateUopWithIndex(i).lqIdx := io.enqLsq.resp(i).lqIdx
updateUopWithIndex(i).sqIdx := io.enqLsq.resp(i).sqIdx
}
// send uops with correct indexes to dispatch queues XSDebug(io.toIntDq.req(i).valid, p"pc 0x${Hexadecimal(io.toIntDq.req(i).bits.cf.pc)} int index $i\n")
// Note that if one of their previous instructions cannot enqueue, they should not enter dispatch queue. XSDebug(io.toFpDq.req(i).valid , p"pc 0x${Hexadecimal(io.toFpDq.req(i).bits.cf.pc )} fp index $i\n")
// We use notBlockedByPrevious here since mapping(i).valid implies there's a valid instruction that can enqueue, XSDebug(io.toLsDq.req(i).valid , p"pc 0x${Hexadecimal(io.toLsDq.req(i).bits.cf.pc )} ls index $i\n")
// thus we don't need to check thisCanOut.
for (i <- 0 until dpParams.DqEnqWidth) {
io.toIntDq(i).bits := updateUopWithIndex(intIndex.io.mapping(i).bits)
io.toIntDq(i).valid := intIndex.io.mapping(i).valid && allResourceReady &&
!thisIsBlocked(intIndex.io.mapping(i).bits) && notBlockedByPrevious(intIndex.io.mapping(i).bits)
// NOTE: floating point instructions are not noSpecExec currently
// remove commit /**/ when fp instructions are possible to be noSpecExec
io.toFpDq(i).bits := updateUopWithIndex(fpIndex.io.mapping(i).bits)
io.toFpDq(i).valid := fpIndex.io.mapping(i).valid && allResourceReady &&
/*!thisIsBlocked(fpIndex.io.mapping(i).bits) && */notBlockedByPrevious(fpIndex.io.mapping(i).bits)
io.toLsDq(i).bits := updateUopWithIndex(lsIndex.io.mapping(i).bits)
io.toLsDq(i).valid := lsIndex.io.mapping(i).valid && allResourceReady &&
!thisIsBlocked(lsIndex.io.mapping(i).bits) && notBlockedByPrevious(lsIndex.io.mapping(i).bits)
XSDebug(io.toIntDq(i).valid, p"pc 0x${Hexadecimal(io.toIntDq(i).bits.cf.pc)} int index $i\n")
XSDebug(io.toFpDq(i).valid , p"pc 0x${Hexadecimal(io.toFpDq(i).bits.cf.pc )} fp index $i\n")
XSDebug(io.toLsDq(i).valid , p"pc 0x${Hexadecimal(io.toLsDq(i).bits.cf.pc )} ls index $i\n")
} }
/** /**
* Part 3: send response to rename when dispatch queue accepts the uop * Part 4: send response to rename when dispatch queue accepts the uop
*/ */
val readyVector = (0 until RenameWidth).map(i => !io.fromRename(i).valid || io.recv(i)) val hasSpecialInstr = Cat((0 until RenameWidth).map(i => io.fromRename(i).valid && (isBlockBackward(i) || isNoSpecExec(i)))).orR
for (i <- 0 until RenameWidth) { for (i <- 0 until RenameWidth) {
io.recv(i) := thisCanActualOut(i) io.recv(i) := thisCanActualOut(i) && io.enqLsq.canAccept && io.enqRoq.canAccept && io.toIntDq.canAccept && io.toFpDq.canAccept && io.toLsDq.canAccept
io.fromRename(i).ready := Cat(readyVector).andR() io.fromRename(i).ready := !hasSpecialInstr && io.enqLsq.canAccept && io.enqRoq.canAccept && io.toIntDq.canAccept && io.toFpDq.canAccept && io.toLsDq.canAccept
XSInfo(io.recv(i), XSInfo(io.recv(i) && io.fromRename(i).valid,
p"pc 0x${Hexadecimal(io.fromRename(i).bits.cf.pc)}, type(${isInt(i)}, ${isFp(i)}, ${isLs(i)}), " + p"pc 0x${Hexadecimal(io.fromRename(i).bits.cf.pc)}, type(${isInt(i)}, ${isFp(i)}, ${isLs(i)}), " +
p"roq ${updateUopWithIndex(i).roqIdx}, lq ${updateUopWithIndex(i).lqIdx}, sq ${updateUopWithIndex(i).sqIdx}, " + p"roq ${updatedUop(i).roqIdx}, lq ${updatedUop(i).lqIdx}, sq ${updatedUop(i).sqIdx})\n"
p"(${intIndex.io.reverseMapping(i).bits}, ${fpIndex.io.reverseMapping(i).bits}, ${lsIndex.io.reverseMapping(i).bits})\n"
) )
io.allocPregs(i).isInt := io.fromRename(i).valid && io.fromRename(i).bits.ctrl.rfWen && (io.fromRename(i).bits.ctrl.ldest =/= 0.U) io.allocPregs(i).isInt := io.fromRename(i).valid && io.fromRename(i).bits.ctrl.rfWen && (io.fromRename(i).bits.ctrl.ldest =/= 0.U)
...@@ -227,7 +183,9 @@ class Dispatch1 extends XSModule { ...@@ -227,7 +183,9 @@ class Dispatch1 extends XSModule {
io.allocPregs(i).preg := io.fromRename(i).bits.pdest io.allocPregs(i).preg := io.fromRename(i).bits.pdest
} }
val renameFireCnt = PopCount(io.recv) val renameFireCnt = PopCount(io.recv)
val enqFireCnt = PopCount(io.toIntDq.map(_.valid && io.toIntDqReady)) + PopCount(io.toFpDq.map(_.valid && io.toFpDqReady)) + PopCount(io.toLsDq.map(_.valid && io.toLsDqReady)) val enqFireCnt = PopCount(io.toIntDq.req.map(_.valid && io.toIntDq.canAccept)) +
PopCount(io.toFpDq.req.map(_.valid && io.toFpDq.canAccept)) +
PopCount(io.toLsDq.req.map(_.valid && io.toLsDq.canAccept))
XSError(enqFireCnt > renameFireCnt, "enqFireCnt should not be greater than renameFireCnt\n") XSError(enqFireCnt > renameFireCnt, "enqFireCnt should not be greater than renameFireCnt\n")
XSPerf("utilization", PopCount(io.fromRename.map(_.valid))) XSPerf("utilization", PopCount(io.fromRename.map(_.valid)))
......
...@@ -3,13 +3,14 @@ package xiangshan.backend.dispatch ...@@ -3,13 +3,14 @@ package xiangshan.backend.dispatch
import chisel3._ import chisel3._
import chisel3.util._ import chisel3.util._
import utils._ import utils._
import xiangshan.backend.decode.SrcType
import xiangshan._ import xiangshan._
import xiangshan.backend.roq.RoqPtr import xiangshan.backend.roq.RoqPtr
class DispatchQueueIO(enqnum: Int, deqnum: Int) extends XSBundle { class DispatchQueueIO(enqnum: Int, deqnum: Int) extends XSBundle {
val enq = Vec(enqnum, Flipped(ValidIO(new MicroOp))) val enq = new Bundle {
val enqReady = Output(Bool()) val canAccept = Output(Bool())
val req = Vec(enqnum, Flipped(ValidIO(new MicroOp)))
}
val deq = Vec(deqnum, DecoupledIO(new MicroOp)) val deq = Vec(deqnum, DecoupledIO(new MicroOp))
val redirect = Flipped(ValidIO(new Redirect)) val redirect = Flipped(ValidIO(new Redirect))
override def cloneType: DispatchQueueIO.this.type = override def cloneType: DispatchQueueIO.this.type =
...@@ -19,7 +20,6 @@ class DispatchQueueIO(enqnum: Int, deqnum: Int) extends XSBundle { ...@@ -19,7 +20,6 @@ class DispatchQueueIO(enqnum: Int, deqnum: Int) extends XSBundle {
// dispatch queue: accepts at most enqnum uops from dispatch1 and dispatches deqnum uops at every clock cycle // dispatch queue: accepts at most enqnum uops from dispatch1 and dispatches deqnum uops at every clock cycle
class DispatchQueue(size: Int, enqnum: Int, deqnum: Int) extends XSModule with HasCircularQueuePtrHelper { class DispatchQueue(size: Int, enqnum: Int, deqnum: Int) extends XSModule with HasCircularQueuePtrHelper {
val io = IO(new DispatchQueueIO(enqnum, deqnum)) val io = IO(new DispatchQueueIO(enqnum, deqnum))
val indexWidth = log2Ceil(size)
val s_invalid :: s_valid:: Nil = Enum(2) val s_invalid :: s_valid:: Nil = Enum(2)
...@@ -28,22 +28,18 @@ class DispatchQueue(size: Int, enqnum: Int, deqnum: Int) extends XSModule with H ...@@ -28,22 +28,18 @@ class DispatchQueue(size: Int, enqnum: Int, deqnum: Int) extends XSModule with H
val stateEntries = RegInit(VecInit(Seq.fill(size)(s_invalid))) val stateEntries = RegInit(VecInit(Seq.fill(size)(s_invalid)))
// head: first valid entry (dispatched entry) // head: first valid entry (dispatched entry)
val headPtr = RegInit(0.U.asTypeOf(new CircularQueuePtr(size))) val headPtr = RegInit(VecInit((0 until deqnum).map(_.U.asTypeOf(new CircularQueuePtr(size)))))
val headPtrMask = UIntToMask(headPtr.value, size) val headPtrMask = UIntToMask(headPtr(0).value, size)
// tail: first invalid entry (free entry) // tail: first invalid entry (free entry)
val tailPtr = RegInit(0.U.asTypeOf(new CircularQueuePtr(size))) val tailPtr = RegInit(VecInit((0 until enqnum).map(_.U.asTypeOf(new CircularQueuePtr(size)))))
val tailPtrMask = UIntToMask(tailPtr.value, size) val tailPtrMask = UIntToMask(tailPtr(0).value, size)
// valid entries counter
// TODO: make ptr a vector to reduce latency? val validCounter = RegInit(0.U(log2Ceil(size + 1).W))
// deq: starting from head ptr val allowEnqueue = RegInit(true.B)
val deqIndex = (0 until deqnum).map(i => headPtr + i.U).map(_.value)
// enq: starting from tail ptr
val enqIndex = (0 until enqnum).map(i => tailPtr + i.U).map(_.value)
val validEntries = distanceBetween(tailPtr, headPtr)
val isTrueEmpty = ~Cat((0 until size).map(i => stateEntries(i) === s_valid)).orR val isTrueEmpty = ~Cat((0 until size).map(i => stateEntries(i) === s_valid)).orR
val canEnqueue = validEntries <= (size - enqnum).U val canEnqueue = allowEnqueue
val canActualEnqueue = canEnqueue && !(io.redirect.valid /*&& !io.redirect.bits.isReplay*/) val canActualEnqueue = canEnqueue && !io.redirect.valid
/** /**
* Part 1: update states and uops when enqueue, dequeue, commit, redirect/replay * Part 1: update states and uops when enqueue, dequeue, commit, redirect/replay
...@@ -58,32 +54,28 @@ class DispatchQueue(size: Int, enqnum: Int, deqnum: Int) extends XSModule with H ...@@ -58,32 +54,28 @@ class DispatchQueue(size: Int, enqnum: Int, deqnum: Int) extends XSModule with H
* (5) redirect (replay): from s_dispatched to s_valid (re-dispatch) * (5) redirect (replay): from s_dispatched to s_valid (re-dispatch)
*/ */
// enqueue: from s_invalid to s_valid // enqueue: from s_invalid to s_valid
io.enqReady := canEnqueue io.enq.canAccept := canEnqueue
for (i <- 0 until enqnum) { for (i <- 0 until enqnum) {
when (io.enq(i).valid && canActualEnqueue) { when (io.enq.req(i).valid && canActualEnqueue) {
uopEntries(enqIndex(i)) := io.enq(i).bits val sel = if (i == 0) 0.U else PopCount(io.enq.req.take(i).map(_.valid))
stateEntries(enqIndex(i)) := s_valid uopEntries(tailPtr(sel).value) := io.enq.req(i).bits
stateEntries(tailPtr(sel).value) := s_valid
} }
} }
// dequeue: from s_valid to s_dispatched // dequeue: from s_valid to s_dispatched
for (i <- 0 until deqnum) { for (i <- 0 until deqnum) {
when (io.deq(i).fire() && !io.redirect.valid) { when (io.deq(i).fire() && !io.redirect.valid) {
stateEntries(deqIndex(i)) := s_invalid stateEntries(headPtr(i).value) := s_invalid
XSError(stateEntries(deqIndex(i)) =/= s_valid, "state of the dispatch entry is not s_valid\n") XSError(stateEntries(headPtr(i).value) =/= s_valid, "state of the dispatch entry is not s_valid\n")
} }
} }
// redirect: cancel uops currently in the queue // redirect: cancel uops currently in the queue
val mispredictionValid = io.redirect.valid //&& io.redirect.bits.isMisPred
val exceptionValid = io.redirect.valid && io.redirect.bits.isException
val flushPipeValid = io.redirect.valid && io.redirect.bits.isFlushPipe
val roqNeedFlush = Wire(Vec(size, Bool()))
val needCancel = Wire(Vec(size, Bool())) val needCancel = Wire(Vec(size, Bool()))
for (i <- 0 until size) { for (i <- 0 until size) {
roqNeedFlush(i) := uopEntries(i.U).roqIdx.needFlush(io.redirect) needCancel(i) := stateEntries(i) =/= s_invalid && uopEntries(i.U).roqIdx.needFlush(io.redirect)
needCancel(i) := stateEntries(i) =/= s_invalid && ((roqNeedFlush(i) && mispredictionValid) || exceptionValid || flushPipeValid)
when (needCancel(i)) { when (needCancel(i)) {
stateEntries(i) := s_invalid stateEntries(i) := s_invalid
...@@ -102,22 +94,26 @@ class DispatchQueue(size: Int, enqnum: Int, deqnum: Int) extends XSModule with H ...@@ -102,22 +94,26 @@ class DispatchQueue(size: Int, enqnum: Int, deqnum: Int) extends XSModule with H
*/ */
// dequeue // dequeue
val numDeqTry = Mux(validEntries > deqnum.U, deqnum.U, validEntries) val currentValidCounter = distanceBetween(tailPtr(0), headPtr(0))
val numDeqTry = Mux(currentValidCounter > deqnum.U, deqnum.U, currentValidCounter)
val numDeqFire = PriorityEncoder(io.deq.zipWithIndex.map{case (deq, i) => val numDeqFire = PriorityEncoder(io.deq.zipWithIndex.map{case (deq, i) =>
// For dequeue, the first entry should never be s_invalid // For dequeue, the first entry should never be s_invalid
// Otherwise, there should be a redirect and tail walks back // Otherwise, there should be a redirect and tail walks back
// in this case, we set numDeq to 0 // in this case, we set numDeq to 0
!deq.fire() && (if (i == 0) true.B else stateEntries(deqIndex(i)) =/= s_invalid) !deq.fire() && (if (i == 0) true.B else stateEntries(headPtr(i).value) =/= s_invalid)
} :+ true.B) } :+ true.B)
val numDeq = Mux(numDeqTry > numDeqFire, numDeqFire, numDeqTry) val numDeq = Mux(numDeqTry > numDeqFire, numDeqFire, numDeqTry)
// agreement with reservation station: don't dequeue when redirect.valid // agreement with reservation station: don't dequeue when redirect.valid
val headPtrNext = Mux(mispredictionValid, headPtr, headPtr + numDeq) for (i <- 0 until deqnum) {
headPtr := Mux(exceptionValid, 0.U.asTypeOf(new CircularQueuePtr(size)), headPtrNext) headPtr(i) := Mux(io.redirect.valid && io.redirect.bits.isUnconditional(),
i.U.asTypeOf(new CircularQueuePtr(size)),
Mux(io.redirect.valid, headPtr(i), headPtr(i) + numDeq))
}
// For branch mis-prediction or memory violation replay, // For branch mis-prediction or memory violation replay,
// we delay updating the indices for one clock cycle. // we delay updating the indices for one clock cycle.
// For now, we simply use PopCount to count #instr cancelled. // For now, we simply use PopCount to count #instr cancelled.
val lastCycleMisprediction = RegNext(io.redirect.valid && !(io.redirect.bits.isException || io.redirect.bits.isFlushPipe)) val lastCycleMisprediction = RegNext(io.redirect.valid && !io.redirect.bits.isUnconditional())
// find the last one's position, starting from headPtr and searching backwards // find the last one's position, starting from headPtr and searching backwards
val validBitVec = VecInit((0 until size).map(i => stateEntries(i) === s_valid)) val validBitVec = VecInit((0 until size).map(i => stateEntries(i) === s_valid))
val loValidBitVec = Cat((0 until size).map(i => validBitVec(i) && headPtrMask(i))) val loValidBitVec = Cat((0 until size).map(i => validBitVec(i) && headPtrMask(i)))
...@@ -125,32 +121,68 @@ class DispatchQueue(size: Int, enqnum: Int, deqnum: Int) extends XSModule with H ...@@ -125,32 +121,68 @@ class DispatchQueue(size: Int, enqnum: Int, deqnum: Int) extends XSModule with H
val flippedFlag = loValidBitVec.orR val flippedFlag = loValidBitVec.orR
val lastOneIndex = size.U - PriorityEncoder(Mux(loValidBitVec.orR, loValidBitVec, hiValidBitVec)) val lastOneIndex = size.U - PriorityEncoder(Mux(loValidBitVec.orR, loValidBitVec, hiValidBitVec))
val walkedTailPtr = Wire(new CircularQueuePtr(size)) val walkedTailPtr = Wire(new CircularQueuePtr(size))
walkedTailPtr.flag := flippedFlag ^ headPtr.flag walkedTailPtr.flag := flippedFlag ^ headPtr(0).flag
walkedTailPtr.value := lastOneIndex walkedTailPtr.value := lastOneIndex
// enqueue // enqueue
val numEnq = Mux(canActualEnqueue, PriorityEncoder(io.enq.map(!_.valid) :+ true.B), 0.U) val numEnq = Mux(io.enq.canAccept, PopCount(io.enq.req.map(_.valid)), 0.U)
XSError(numEnq =/= 0.U && (mispredictionValid || exceptionValid), "should not enqueue when redirect\n") val exceptionValid = io.redirect.valid && io.redirect.bits.isUnconditional()
tailPtr := Mux(exceptionValid, tailPtr(0) := Mux(exceptionValid,
0.U.asTypeOf(new CircularQueuePtr(size)), 0.U.asTypeOf(new CircularQueuePtr(size)),
Mux(lastCycleMisprediction, Mux(io.redirect.valid,
Mux(isTrueEmpty, headPtr, walkedTailPtr), tailPtr(0),
tailPtr + numEnq) Mux(lastCycleMisprediction,
Mux(isTrueEmpty, headPtr(0), walkedTailPtr),
tailPtr(0) + numEnq))
) )
val lastCycleException = RegNext(exceptionValid)
val lastLastCycleMisprediction = RegNext(lastCycleMisprediction)
for (i <- 1 until enqnum) {
tailPtr(i) := Mux(exceptionValid,
i.U.asTypeOf(new CircularQueuePtr(size)),
Mux(io.redirect.valid,
tailPtr(i),
Mux(lastLastCycleMisprediction,
tailPtr(0) + i.U,
tailPtr(i) + numEnq))
)
}
// update valid counter and allowEnqueue reg
validCounter := Mux(exceptionValid,
0.U,
Mux(io.redirect.valid,
validCounter,
Mux(lastLastCycleMisprediction,
currentValidCounter,
validCounter + numEnq - numDeq)
)
)
allowEnqueue := Mux(io.redirect.valid,
false.B,
Mux(lastLastCycleMisprediction,
currentValidCounter <= (size - enqnum).U,
// To optimize timing, we don't use numDeq here.
// It affects cases when validCount + numEnq - numDeq <= (size - enqnum).U.
// For example, there're 10 empty entries with 6 enqueue and 2 dequeue.
// However, since dispatch queue size > (numEnq + numDeq),
// even if we allow enqueue, they cannot be dispatched immediately.
validCounter + numEnq <= (size - enqnum).U
)
)
/** /**
* Part 3: set output and input * Part 3: set output and input
*/ */
// TODO: remove this when replay moves to roq // TODO: remove this when replay moves to roq
for (i <- 0 until deqnum) { for (i <- 0 until deqnum) {
io.deq(i).bits := uopEntries(deqIndex(i)) io.deq(i).bits := uopEntries(headPtr(i).value)
// do not dequeue when io.redirect valid because it may cause dispatchPtr work improperly // do not dequeue when io.redirect valid because it may cause dispatchPtr work improperly
io.deq(i).valid := stateEntries(deqIndex(i)) === s_valid && !lastCycleMisprediction// && !io.redirect.valid io.deq(i).valid := stateEntries(headPtr(i).value) === s_valid && !lastCycleMisprediction
} }
// debug: dump dispatch queue states // debug: dump dispatch queue states
XSDebug(p"head: $headPtr, tail: $tailPtr\n") XSDebug(p"head: ${headPtr(0)}, tail: ${tailPtr(0)}\n")
XSDebug(p"state: ") XSDebug(p"state: ")
stateEntries.reverse.foreach { s => stateEntries.reverse.foreach { s =>
XSDebug(false, s === s_invalid, "-") XSDebug(false, s === s_invalid, "-")
...@@ -159,13 +191,12 @@ class DispatchQueue(size: Int, enqnum: Int, deqnum: Int) extends XSModule with H ...@@ -159,13 +191,12 @@ class DispatchQueue(size: Int, enqnum: Int, deqnum: Int) extends XSModule with H
XSDebug(false, true.B, "\n") XSDebug(false, true.B, "\n")
XSDebug(p"ptr: ") XSDebug(p"ptr: ")
(0 until size).reverse.foreach { i => (0 until size).reverse.foreach { i =>
val isPtr = i.U === headPtr.value || i.U === tailPtr.value val isPtr = i.U === headPtr(0).value || i.U === tailPtr(0).value
XSDebug(false, isPtr, "^") XSDebug(false, isPtr, "^")
XSDebug(false, !isPtr, " ") XSDebug(false, !isPtr, " ")
} }
XSDebug(false, true.B, "\n") XSDebug(false, true.B, "\n")
XSError(isAfter(headPtr, tailPtr), p"assert greaterOrEqualThan(tailPtr: $tailPtr, headPtr: $headPtr) failed\n") XSError(isAfter(headPtr(0), tailPtr(0)), p"assert greaterOrEqualThan(tailPtr: ${tailPtr(0)}, headPtr: ${headPtr(0)}) failed\n")
XSPerf("utilization", PopCount(stateEntries.map(_ =/= s_invalid))) XSPerf("utilization", PopCount(stateEntries.map(_ =/= s_invalid)))
} }
...@@ -19,7 +19,7 @@ class AluExeUnit extends Exu(aluExeUnitCfg) ...@@ -19,7 +19,7 @@ class AluExeUnit extends Exu(aluExeUnitCfg)
XSDebug(io.fromInt.valid || io.redirect.valid, XSDebug(io.fromInt.valid || io.redirect.valid,
p"fromInt(${io.fromInt.valid} ${io.fromInt.ready}) toInt(${io.toInt.valid} ${io.toInt.ready})" + p"fromInt(${io.fromInt.valid} ${io.fromInt.ready}) toInt(${io.toInt.valid} ${io.toInt.ready})" +
p"Redirect:(${io.redirect.valid} ${io.redirect.bits.isException}${io.redirect.bits.isFlushPipe}${io.redirect.bits.isMisPred}${io.redirect.bits.isReplay}) roqIdx:${io.redirect.bits.roqIdx}\n", p"Redirect:(${io.redirect.valid}) roqIdx:${io.redirect.bits.roqIdx}\n",
) )
XSDebug(io.fromInt.valid, XSDebug(io.fromInt.valid,
p"src1:${Hexadecimal(io.fromInt.bits.src1)} src2:${Hexadecimal(io.fromInt.bits.src2)} " + p"src1:${Hexadecimal(io.fromInt.bits.src1)} src2:${Hexadecimal(io.fromInt.bits.src2)} " +
......
...@@ -80,10 +80,8 @@ class JumpExeUnit extends Exu(jumpExeUnitCfg) ...@@ -80,10 +80,8 @@ class JumpExeUnit extends Exu(jumpExeUnitCfg)
when(csr.io.out.valid){ when(csr.io.out.valid){
io.toInt.bits.redirectValid := csr.csrio.redirectOut.valid io.toInt.bits.redirectValid := csr.csrio.redirectOut.valid
io.toInt.bits.redirect.brTag := uop.brTag io.toInt.bits.redirect.brTag := uop.brTag
io.toInt.bits.redirect.isException := false.B io.toInt.bits.redirect.level := RedirectLevel.flushAfter
io.toInt.bits.redirect.isMisPred := false.B io.toInt.bits.redirect.interrupt := DontCare
io.toInt.bits.redirect.isFlushPipe := false.B
io.toInt.bits.redirect.isReplay := false.B
io.toInt.bits.redirect.roqIdx := uop.roqIdx io.toInt.bits.redirect.roqIdx := uop.roqIdx
io.toInt.bits.redirect.target := csr.csrio.redirectOut.bits io.toInt.bits.redirect.target := csr.csrio.redirectOut.bits
io.toInt.bits.redirect.pc := uop.cf.pc io.toInt.bits.redirect.pc := uop.cf.pc
......
...@@ -65,12 +65,11 @@ class MulDivExeUnit extends Exu(mulDivExeUnitCfg) { ...@@ -65,12 +65,11 @@ class MulDivExeUnit extends Exu(mulDivExeUnitCfg) {
div.ctrl.isW := isW div.ctrl.isW := isW
div.ctrl.sign := isDivSign div.ctrl.sign := isDivSign
XSDebug(io.fromInt.valid, "In(%d %d) Out(%d %d) Redirect:(%d %d %d) brTag:%x\n", XSDebug(io.fromInt.valid, "In(%d %d) Out(%d %d) Redirect:(%d %d) brTag:%x\n",
io.fromInt.valid, io.fromInt.ready, io.fromInt.valid, io.fromInt.ready,
io.toInt.valid, io.toInt.ready, io.toInt.valid, io.toInt.ready,
io.redirect.valid, io.redirect.valid,
io.redirect.bits.isException, io.redirect.bits.level,
io.redirect.bits.isFlushPipe,
io.redirect.bits.brTag.value io.redirect.bits.brTag.value
) )
XSDebug(io.fromInt.valid, "src1:%x src2:%x pc:%x\n", src1, src2, io.fromInt.bits.uop.cf.pc) XSDebug(io.fromInt.valid, "src1:%x src2:%x pc:%x\n", src1, src2, io.fromInt.bits.uop.cf.pc)
......
...@@ -59,10 +59,8 @@ class Alu extends FunctionUnit with HasRedirectOut { ...@@ -59,10 +59,8 @@ class Alu extends FunctionUnit with HasRedirectOut {
redirectOut.pc := uop.cf.pc redirectOut.pc := uop.cf.pc
redirectOut.target := Mux(!taken && isBranch, snpc, target) redirectOut.target := Mux(!taken && isBranch, snpc, target)
redirectOut.brTag := uop.brTag redirectOut.brTag := uop.brTag
redirectOut.isException := false.B redirectOut.level := RedirectLevel.flushAfter
redirectOut.isMisPred := DontCare // check this in brq redirectOut.interrupt := DontCare
redirectOut.isFlushPipe := false.B
redirectOut.isReplay := false.B
redirectOut.roqIdx := uop.roqIdx redirectOut.roqIdx := uop.roqIdx
brUpdate := uop.cf.brUpdate brUpdate := uop.cf.brUpdate
......
...@@ -597,58 +597,92 @@ class CSR extends FunctionUnit with HasCSRConst ...@@ -597,58 +597,92 @@ class CSR extends FunctionUnit with HasCSRConst
tlbBundle.priv.imode := priviledgeMode tlbBundle.priv.imode := priviledgeMode
tlbBundle.priv.dmode := Mux(mstatusStruct.mprv.asBool, mstatusStruct.mpp, priviledgeMode) tlbBundle.priv.dmode := Mux(mstatusStruct.mprv.asBool, mstatusStruct.mpp, priviledgeMode)
val hasInstrPageFault = csrio.exception.bits.cf.exceptionVec(instrPageFault) && csrio.exception.valid // Branch control
val hasLoadPageFault = csrio.exception.bits.cf.exceptionVec(loadPageFault) && csrio.exception.valid val retTarget = Wire(UInt(VAddrBits.W))
val hasStorePageFault = csrio.exception.bits.cf.exceptionVec(storePageFault) && csrio.exception.valid val resetSatp = addr === Satp.U && wen // write to satp will cause the pipeline be flushed
val hasStoreAddrMisaligned = csrio.exception.bits.cf.exceptionVec(storeAddrMisaligned) && csrio.exception.valid csrio.redirectOut.valid := valid && func === CSROpType.jmp && !isEcall
val hasLoadAddrMisaligned = csrio.exception.bits.cf.exceptionVec(loadAddrMisaligned) && csrio.exception.valid csrio.redirectOut.bits := retTarget
flushPipe := resetSatp
XSDebug(csrio.redirectOut.valid, "redirect to %x, pc=%x\n", csrio.redirectOut.bits, cfIn.pc)
// mtval write logic retTarget := DontCare
val memExceptionAddr = SignExt(csrio.memExceptionVAddr, XLEN) // val illegalEret = TODO
when(hasInstrPageFault || hasLoadPageFault || hasStorePageFault){
val tval = Mux( when (valid && isMret) {
hasInstrPageFault, val mstatusOld = WireInit(mstatus.asTypeOf(new MstatusStruct))
Mux( val mstatusNew = WireInit(mstatus.asTypeOf(new MstatusStruct))
csrio.exception.bits.cf.crossPageIPFFix, mstatusNew.ie.m := mstatusOld.pie.m
SignExt(csrio.exception.bits.cf.pc + 2.U, XLEN), priviledgeMode := mstatusOld.mpp
SignExt(csrio.exception.bits.cf.pc, XLEN) mstatusNew.pie.m := true.B
), mstatusNew.mpp := ModeU
memExceptionAddr mstatusNew.mprv := 0.U
) mstatus := mstatusNew.asUInt
when(priviledgeMode === ModeM){ // lr := false.B
mtval := tval retTarget := mepc(VAddrBits-1, 0)
}.otherwise{
stval := tval
}
} }
when(hasLoadAddrMisaligned || hasStoreAddrMisaligned) when (valid && isSret && !illegalSModeSret) {
{ val mstatusOld = WireInit(mstatus.asTypeOf(new MstatusStruct))
mtval := memExceptionAddr val mstatusNew = WireInit(mstatus.asTypeOf(new MstatusStruct))
mstatusNew.ie.s := mstatusOld.pie.s
priviledgeMode := Cat(0.U(1.W), mstatusOld.spp)
mstatusNew.pie.s := true.B
mstatusNew.spp := ModeU
mstatus := mstatusNew.asUInt
mstatusNew.mprv := 0.U
// lr := false.B
retTarget := sepc(VAddrBits-1, 0)
} }
// Exception and Intr when (valid && isUret) {
val mstatusOld = WireInit(mstatus.asTypeOf(new MstatusStruct))
val mstatusNew = WireInit(mstatus.asTypeOf(new MstatusStruct))
// mstatusNew.mpp.m := ModeU //TODO: add mode U
mstatusNew.ie.u := mstatusOld.pie.u
priviledgeMode := ModeU
mstatusNew.pie.u := true.B
mstatus := mstatusNew.asUInt
retTarget := uepc(VAddrBits-1, 0)
}
// interrupts XSDebug(csrio.redirectOut.valid,
"Rediret %x isSret:%d retTarget:%x sepc:%x cfInpc:%x valid:%d\n",
csrio.redirectOut.bits, isSret, retTarget, sepc, cfIn.pc, valid
)
io.in.ready := true.B
io.out.valid := valid
/**
* Exception and Intr
*/
val ideleg = (mideleg & mip.asUInt) val ideleg = (mideleg & mip.asUInt)
def priviledgedEnableDetect(x: Bool): Bool = Mux(x, ((priviledgeMode === ModeS) && mstatusStruct.ie.s) || (priviledgeMode < ModeS), def priviledgedEnableDetect(x: Bool): Bool = Mux(x, ((priviledgeMode === ModeS) && mstatusStruct.ie.s) || (priviledgeMode < ModeS),
((priviledgeMode === ModeM) && mstatusStruct.ie.m) || (priviledgeMode < ModeM)) ((priviledgeMode === ModeM) && mstatusStruct.ie.m) || (priviledgeMode < ModeM))
// send interrupt information to ROQ
val intrVecEnable = Wire(Vec(12, Bool())) val intrVecEnable = Wire(Vec(12, Bool()))
intrVecEnable.zip(ideleg.asBools).map{case(x,y) => x := priviledgedEnableDetect(y)} intrVecEnable.zip(ideleg.asBools).map{case(x,y) => x := priviledgedEnableDetect(y)}
val intrVec = mie(11,0) & mip.asUInt & intrVecEnable.asUInt val intrVec = mie(11,0) & mip.asUInt & intrVecEnable.asUInt
val intrBitSet = intrVec.orR() val intrBitSet = intrVec.orR()
csrio.interrupt := intrBitSet csrio.interrupt := intrBitSet
val intrNO = IntPriority.foldRight(0.U)((i: Int, sum: UInt) => Mux(intrVec(i), i.U, sum))
val raiseIntr = intrBitSet && csrio.exception.valid && csrio.isInterrupt
XSDebug(raiseIntr, "interrupt: pc=0x%x, %d\n", csrio.exception.bits.cf.pc, intrNO)
mipWire.t.m := csrio.externalInterrupt.mtip mipWire.t.m := csrio.externalInterrupt.mtip
mipWire.s.m := csrio.externalInterrupt.msip mipWire.s.m := csrio.externalInterrupt.msip
mipWire.e.m := csrio.externalInterrupt.meip mipWire.e.m := csrio.externalInterrupt.meip
// interrupts
val intrNO = IntPriority.foldRight(0.U)((i: Int, sum: UInt) => Mux(intrVec(i), i.U, sum))
val raiseIntr = csrio.exception.valid && csrio.isInterrupt
XSDebug(raiseIntr, "interrupt: pc=0x%x, %d\n", csrio.exception.bits.cf.pc, intrNO)
// exceptions // exceptions
val raiseException = csrio.exception.valid && !csrio.isInterrupt
val hasInstrPageFault = csrio.exception.bits.cf.exceptionVec(instrPageFault) && raiseException
val hasLoadPageFault = csrio.exception.bits.cf.exceptionVec(loadPageFault) && raiseException
val hasStorePageFault = csrio.exception.bits.cf.exceptionVec(storePageFault) && raiseException
val hasStoreAddrMisaligned = csrio.exception.bits.cf.exceptionVec(storeAddrMisaligned) && raiseException
val hasLoadAddrMisaligned = csrio.exception.bits.cf.exceptionVec(loadAddrMisaligned) && raiseException
val csrExceptionVec = Wire(Vec(16, Bool())) val csrExceptionVec = Wire(Vec(16, Bool()))
csrExceptionVec.map(_ := false.B) csrExceptionVec.map(_ := false.B)
csrExceptionVec(breakPoint) := io.in.valid && isEbreak csrExceptionVec(breakPoint) := io.in.valid && isEbreak
...@@ -676,20 +710,8 @@ class CSR extends FunctionUnit with HasCSRConst ...@@ -676,20 +710,8 @@ class CSR extends FunctionUnit with HasCSRConst
// } // }
val raiseExceptionIntr = csrio.exception.valid val raiseExceptionIntr = csrio.exception.valid
val retTarget = Wire(UInt(VAddrBits.W))
val resetSatp = addr === Satp.U && wen // write to satp will cause the pipeline be flushed
csrio.redirectOut.valid := valid && func === CSROpType.jmp && !isEcall
csrio.redirectOut.bits := retTarget
flushPipe := resetSatp
XSDebug(csrio.redirectOut.valid, "redirect to %x, pc=%x\n", csrio.redirectOut.bits, cfIn.pc)
XSDebug(raiseExceptionIntr, "int/exc: pc %x int (%d):%x exc: (%d):%x\n", XSDebug(raiseExceptionIntr, "int/exc: pc %x int (%d):%x exc: (%d):%x\n",
csrio.exception.bits.cf.pc, csrio.exception.bits.cf.pc, intrNO, intrVec, exceptionNO, raiseExceptionVec.asUInt
intrNO,
csrio.exception.bits.cf.intrVec.asUInt,
exceptionNO,
raiseExceptionVec.asUInt
) )
XSDebug(raiseExceptionIntr, XSDebug(raiseExceptionIntr,
"pc %x mstatus %x mideleg %x medeleg %x mode %x\n", "pc %x mstatus %x mideleg %x medeleg %x mode %x\n",
...@@ -700,53 +722,35 @@ class CSR extends FunctionUnit with HasCSRConst ...@@ -700,53 +722,35 @@ class CSR extends FunctionUnit with HasCSRConst
priviledgeMode priviledgeMode
) )
// Branch control // mtval write logic
val memExceptionAddr = SignExt(csrio.memExceptionVAddr, XLEN)
when(hasInstrPageFault || hasLoadPageFault || hasStorePageFault){
val tval = Mux(
hasInstrPageFault,
Mux(
csrio.exception.bits.cf.crossPageIPFFix,
SignExt(csrio.exception.bits.cf.pc + 2.U, XLEN),
SignExt(csrio.exception.bits.cf.pc, XLEN)
),
memExceptionAddr
)
when(priviledgeMode === ModeM){
mtval := tval
}.otherwise{
stval := tval
}
}
when(hasLoadAddrMisaligned || hasStoreAddrMisaligned)
{
mtval := memExceptionAddr
}
val deleg = Mux(raiseIntr, mideleg , medeleg) val deleg = Mux(raiseIntr, mideleg , medeleg)
// val delegS = ((deleg & (1 << (causeNO & 0xf))) != 0) && (priviledgeMode < ModeM); // val delegS = ((deleg & (1 << (causeNO & 0xf))) != 0) && (priviledgeMode < ModeM);
val delegS = (deleg(causeNO(3,0))) && (priviledgeMode < ModeM) val delegS = (deleg(causeNO(3,0))) && (priviledgeMode < ModeM)
val tvalWen = !(hasInstrPageFault || hasLoadPageFault || hasStorePageFault || hasLoadAddrMisaligned || hasStoreAddrMisaligned) || raiseIntr // TODO: need check val tvalWen = !(hasInstrPageFault || hasLoadPageFault || hasStorePageFault || hasLoadAddrMisaligned || hasStoreAddrMisaligned) || raiseIntr // TODO: need check
csrio.trapTarget := Mux(delegS, stvec, mtvec)(VAddrBits-1, 0) csrio.trapTarget := Mux(delegS, stvec, mtvec)(VAddrBits-1, 0)
retTarget := DontCare
// val illegalEret = TODO
when (valid && isMret) {
val mstatusOld = WireInit(mstatus.asTypeOf(new MstatusStruct))
val mstatusNew = WireInit(mstatus.asTypeOf(new MstatusStruct))
mstatusNew.ie.m := mstatusOld.pie.m
priviledgeMode := mstatusOld.mpp
mstatusNew.pie.m := true.B
mstatusNew.mpp := ModeU
mstatusNew.mprv := 0.U
mstatus := mstatusNew.asUInt
// lr := false.B
retTarget := mepc(VAddrBits-1, 0)
}
when (valid && isSret && !illegalSModeSret) {
val mstatusOld = WireInit(mstatus.asTypeOf(new MstatusStruct))
val mstatusNew = WireInit(mstatus.asTypeOf(new MstatusStruct))
mstatusNew.ie.s := mstatusOld.pie.s
priviledgeMode := Cat(0.U(1.W), mstatusOld.spp)
mstatusNew.pie.s := true.B
mstatusNew.spp := ModeU
mstatus := mstatusNew.asUInt
mstatusNew.mprv := 0.U
// lr := false.B
retTarget := sepc(VAddrBits-1, 0)
}
when (valid && isUret) {
val mstatusOld = WireInit(mstatus.asTypeOf(new MstatusStruct))
val mstatusNew = WireInit(mstatus.asTypeOf(new MstatusStruct))
// mstatusNew.mpp.m := ModeU //TODO: add mode U
mstatusNew.ie.u := mstatusOld.pie.u
priviledgeMode := ModeU
mstatusNew.pie.u := true.B
mstatus := mstatusNew.asUInt
retTarget := uepc(VAddrBits-1, 0)
}
when (raiseExceptionIntr) { when (raiseExceptionIntr) {
val mstatusOld = WireInit(mstatus.asTypeOf(new MstatusStruct)) val mstatusOld = WireInit(mstatus.asTypeOf(new MstatusStruct))
...@@ -775,40 +779,17 @@ class CSR extends FunctionUnit with HasCSRConst ...@@ -775,40 +779,17 @@ class CSR extends FunctionUnit with HasCSRConst
mstatus := mstatusNew.asUInt mstatus := mstatusNew.asUInt
} }
io.in.ready := true.B
io.out.valid := valid
XSDebug(csrio.redirectOut.valid,
"Rediret %x raiseExcepIntr:%d isSret:%d retTarget:%x sepc:%x delegs:%d deleg:%x cfInpc:%x valid:%d\n",
csrio.redirectOut.bits,
raiseExceptionIntr,
isSret,
retTarget,
sepc,
delegS,
deleg,
cfIn.pc,
valid
)
XSDebug(raiseExceptionIntr && delegS, XSDebug(raiseExceptionIntr && delegS,
"Red(%d, %x) raiseExcepIntr:%d isSret:%d retTarget:%x sepc:%x delegs:%d deleg:%x cfInpc:%x valid:%d\n", "Red(%d, %x) raiseExcepIntr:%d isSret:%d sepc:%x delegs:%d deleg:%x\n",
csrio.redirectOut.valid, csrio.redirectOut.valid, csrio.redirectOut.bits, raiseExceptionIntr,
csrio.redirectOut.bits, isSret, sepc, delegS, deleg
raiseExceptionIntr,
isSret,
retTarget,
sepc,
delegS,
deleg,
cfIn.pc,
valid
) )
XSDebug(raiseExceptionIntr && delegS, "sepc is writen!!! pc:%x\n", cfIn.pc) XSDebug(raiseExceptionIntr && delegS, "sepc is writen!!! pc:%x\n", cfIn.pc)
// perfcnt /**
* Performance counters
*/
val perfCntList = Map( val perfCntList = Map(
// "Mcycle" -> (0xb00, "perfCntCondMcycle" ), // "Mcycle" -> (0xb00, "perfCntCondMcycle" ),
// "Minstret" -> (0xb02, "perfCntCondMinstret" ), // "Minstret" -> (0xb02, "perfCntCondMinstret" ),
......
...@@ -11,7 +11,7 @@ import xiangshan.backend.decode.isa._ ...@@ -11,7 +11,7 @@ import xiangshan.backend.decode.isa._
trait HasRedirectOut { this: RawModule => trait HasRedirectOut { this: RawModule =>
val redirectOutValid = IO(Output(Bool())) val redirectOutValid = IO(Output(Bool()))
val redirectOut = IO(Output(new Redirect)) val redirectOut = IO(Output(new Redirect))
val brUpdate = IO(Output(new BranchUpdateInfo)) val brUpdate = IO(Output(new CfiUpdateInfo))
} }
class Jump extends FunctionUnit with HasRedirectOut { class Jump extends FunctionUnit with HasRedirectOut {
...@@ -35,16 +35,14 @@ class Jump extends FunctionUnit with HasRedirectOut { ...@@ -35,16 +35,14 @@ class Jump extends FunctionUnit with HasRedirectOut {
redirectOut.pc := uop.cf.pc redirectOut.pc := uop.cf.pc
redirectOut.target := target redirectOut.target := target
redirectOut.brTag := uop.brTag redirectOut.brTag := uop.brTag
redirectOut.isException := false.B redirectOut.level := RedirectLevel.flushAfter
redirectOut.isFlushPipe := false.B redirectOut.interrupt := DontCare
redirectOut.isMisPred := DontCare // check this in brq
redirectOut.isReplay := false.B
redirectOut.roqIdx := uop.roqIdx redirectOut.roqIdx := uop.roqIdx
brUpdate := uop.cf.brUpdate brUpdate := uop.cf.brUpdate
brUpdate.pc := uop.cf.pc brUpdate.pc := uop.cf.pc
brUpdate.target := target brUpdate.target := target
brUpdate.brTarget := target // DontCare brUpdate.brTarget := target
brUpdate.taken := true.B brUpdate.taken := true.B
// Output // Output
...@@ -56,14 +54,13 @@ class Jump extends FunctionUnit with HasRedirectOut { ...@@ -56,14 +54,13 @@ class Jump extends FunctionUnit with HasRedirectOut {
io.out.bits.data := res io.out.bits.data := res
// NOTE: the debug info is for one-cycle exec, if FMV needs multi-cycle, may needs change it // NOTE: the debug info is for one-cycle exec, if FMV needs multi-cycle, may needs change it
XSDebug(io.in.valid, "In(%d %d) Out(%d %d) Redirect:(%d %d %d %d) brTag:%x\n", XSDebug(io.in.valid, "In(%d %d) Out(%d %d) Redirect:(%d %d %d) brTag:%x\n",
io.in.valid, io.in.valid,
io.in.ready, io.in.ready,
io.out.valid, io.out.valid,
io.out.ready, io.out.ready,
io.redirectIn.valid, io.redirectIn.valid,
io.redirectIn.bits.isException, io.redirectIn.bits.level,
io.redirectIn.bits.isFlushPipe,
redirectHit, redirectHit,
io.redirectIn.bits.brTag.value io.redirectIn.bits.brTag.value
) )
......
...@@ -140,6 +140,7 @@ class DivSqrt extends FPUSubModule { ...@@ -140,6 +140,7 @@ class DivSqrt extends FPUSubModule {
// 53 + 2 + 2 = 57 bits are needed, but 57 % log2(4) != 0, use 58 bits instead // 53 + 2 + 2 = 57 bits are needed, but 57 % log2(4) != 0, use 58 bits instead
val mantDivSqrt = Module(new MantDivSqrt(D_MANT_WIDTH+2+2+1)) val mantDivSqrt = Module(new MantDivSqrt(D_MANT_WIDTH+2+2+1))
mantDivSqrt.io.kill := kill
mantDivSqrt.io.out.ready := true.B mantDivSqrt.io.out.ready := true.B
mantDivSqrt.io.in.valid := state === s_start mantDivSqrt.io.in.valid := state === s_start
mantDivSqrt.io.in.bits.a := Mux(isDivReg || aIsOddExp, Cat(aMantReg, 0.U(5.W)), Cat(0.U(1.W), aMantReg, 0.U(4.W))) mantDivSqrt.io.in.bits.a := Mux(isDivReg || aIsOddExp, Cat(aMantReg, 0.U(5.W)), Cat(0.U(1.W), aMantReg, 0.U(4.W)))
......
...@@ -11,6 +11,7 @@ class MantDivSqrt(len: Int) extends Module{ ...@@ -11,6 +11,7 @@ class MantDivSqrt(len: Int) extends Module{
val a, b = UInt(len.W) val a, b = UInt(len.W)
val isDiv = Bool() val isDiv = Bool()
})) }))
val kill = Input(Bool())
val out = DecoupledIO(new Bundle() { val out = DecoupledIO(new Bundle() {
val quotient = UInt(len.W) val quotient = UInt(len.W)
val isZeroRem = Bool() val isZeroRem = Bool()
...@@ -45,6 +46,7 @@ class MantDivSqrt(len: Int) extends Module{ ...@@ -45,6 +46,7 @@ class MantDivSqrt(len: Int) extends Module{
when(io.out.fire()){ state := s_idle } when(io.out.fire()){ state := s_idle }
} }
} }
when(io.kill){ state := s_idle }
val ws, wc = Reg(UInt((len+4).W)) val ws, wc = Reg(UInt((len+4).W))
......
...@@ -167,33 +167,58 @@ class ReservationStationCtrl ...@@ -167,33 +167,58 @@ class ReservationStationCtrl
} }
// redirect and feedback // redirect and feedback && wakeup
//
for (i <- 0 until iqSize) { for (i <- 0 until iqSize) {
val cnt = cntQueue(idxQueue(i)) val cnt = cntQueue(idxQueue(i))
when (!(deqIdx === i.U && deqValid)) {
if (i != 0) { // TODO: combine the two case if (i != 0) { // TODO: combine the two case
val nextIdx = i.U - moveMask(i-1) val nextIdx = i.U - moveMask(i-1)
// cnt
when (stateQueue(i)===s_replay) { when (stateQueue(i)===s_replay) {
when (cnt===0.U) { stateQueue(nextIdx) := s_valid } when (cnt===0.U) { stateQueue(nextIdx) := s_valid }
.otherwise { cnt := cnt - 1.U } .otherwise { cnt := cnt - 1.U }
} }
// feedback
when (fbMatchVec(i)) { when (fbMatchVec(i)) {
stateQueue(nextIdx) := Mux(fbHit, s_idle, s_replay) stateQueue(nextIdx) := Mux(fbHit, s_idle, s_replay)
cnt := Mux(fbHit, cnt, (replayDelay-1).U) cnt := Mux(fbHit, cnt, (replayDelay-1).U)
} }
// redirect
when (redHitVec(i)) { stateQueue(nextIdx) := s_idle } when (redHitVec(i)) { stateQueue(nextIdx) := s_idle }
// wakeup
val hitVec = io.data.srcUpdate(idxQueue(i))
for (j <- 0 until srcNum) {
when (hitVec(j) && validQueue(i)) {
srcQueue(nextIdx)(j) := true.B
XSDebug(p"srcHit: i:${i.U} j:${j.U} moveMask(${i.U}):${moveMask(i)} nextIdx:${nextIdx}")
}
}
} else { when (!moveMask(i)) { } else { when (!moveMask(i)) {
val nextIdx = i val nextIdx = i
// cnt
when (stateQueue(i)===s_replay) { when (stateQueue(i)===s_replay) {
when (cnt===0.U) { stateQueue(nextIdx) := s_valid } when (cnt===0.U) { stateQueue(nextIdx) := s_valid }
.otherwise { cnt := cnt - 1.U } .otherwise { cnt := cnt - 1.U }
} }
// feedback
when (fbMatchVec(i)) { when (fbMatchVec(i)) {
stateQueue(nextIdx) := Mux(fbHit, s_idle, s_replay) stateQueue(nextIdx) := Mux(fbHit, s_idle, s_replay)
cnt := Mux(fbHit, cnt, (replayDelay-1).U) cnt := Mux(fbHit, cnt, (replayDelay-1).U)
} }
// redirect
when (redHitVec(i)) { stateQueue(nextIdx) := s_idle } when (redHitVec(i)) { stateQueue(nextIdx) := s_idle }
// wakeup
val hitVec = io.data.srcUpdate(idxQueue(i))
for (j <- 0 until srcNum) {
when (hitVec(j) && validQueue(i)) {
srcQueue(nextIdx)(j) := true.B
XSDebug(p"srcHit: i:${i.U} j:${j.U} moveMask(${i.U}):${moveMask(i)} nextIdx:${nextIdx}")
}
}
}} }}
}
} }
// output // output
...@@ -234,17 +259,6 @@ class ReservationStationCtrl ...@@ -234,17 +259,6 @@ class ReservationStationCtrl
p"type:${srcTypeSeq(2)}\n") p"type:${srcTypeSeq(2)}\n")
} }
// wakeup
for(i <- 0 until IssQueSize) {
val hitVec = io.data.srcUpdate(idxQueue(i))
for(j <- 0 until srcNum) {
when (hitVec(j) && validQueue(i)) {
srcQueue(i.U - moveMask(i))(j) := true.B
XSDebug(p"srcHit: i:${i.U} j:${j.U}\n")
}
}
}
// other to Data // other to Data
io.data.enqPtr := idxQueue(Mux(tailPtr.flag, deqIdx, tailPtr.value)) io.data.enqPtr := idxQueue(Mux(tailPtr.flag, deqIdx, tailPtr.value))
io.data.deqPtr.valid := selValid io.data.deqPtr.valid := selValid
...@@ -454,4 +468,4 @@ class ReservationStationData ...@@ -454,4 +468,4 @@ class ReservationStationData
p"${Binary(io.ctrl.srcUpdate(i).asUInt)}|${uop(i).pdest}:${uop(i).ctrl.rfWen}:" + p"${Binary(io.ctrl.srcUpdate(i).asUInt)}|${uop(i).pdest}:${uop(i).ctrl.rfWen}:" +
p"${uop(i).ctrl.fpWen}|${uop(i).roqIdx} |${Hexadecimal(uop(i).cf.pc)}\n") p"${uop(i).ctrl.fpWen}|${uop(i).roqIdx} |${Hexadecimal(uop(i).cf.pc)}\n")
} }
} }
\ No newline at end of file
...@@ -164,4 +164,17 @@ package object backend { ...@@ -164,4 +164,17 @@ package object backend {
def apply() = UInt(2.W) def apply() = UInt(2.W)
} }
object SelImm {
def IMM_X = "b111".U
def IMM_S = "b000".U
def IMM_SB = "b001".U
def IMM_U = "b010".U
def IMM_UJ = "b011".U
def IMM_I = "b100".U
def IMM_Z = "b101".U
def INVALID_INSTR = "b110".U
def apply() = UInt(3.W)
}
} }
...@@ -3,7 +3,7 @@ package xiangshan.backend.rename ...@@ -3,7 +3,7 @@ package xiangshan.backend.rename
import chisel3._ import chisel3._
import chisel3.util._ import chisel3.util._
import xiangshan._ import xiangshan._
import utils.{CircularQueuePtr, HasCircularQueuePtrHelper, XSDebug} import utils._
import xiangshan.backend.brq.BrqPtr import xiangshan.backend.brq.BrqPtr
trait HasFreeListConsts extends HasXSParameter { trait HasFreeListConsts extends HasXSParameter {
...@@ -49,7 +49,7 @@ class FreeList extends XSModule with HasFreeListConsts with HasCircularQueuePtrH ...@@ -49,7 +49,7 @@ class FreeList extends XSModule with HasFreeListConsts with HasCircularQueuePtrH
// do checkpoints // do checkpoints
// val cpReqs = Vec(RenameWidth, Flipped(ValidIO(new BrqPtr))) // val cpReqs = Vec(RenameWidth, Flipped(ValidIO(new BrqPtr)))
val walk = Flipped(ValidIO(UInt(log2Up(RenameWidth).W))) val walk = Flipped(ValidIO(UInt(log2Up(CommitWidth + 1).W)))
// dealloc phy regs // dealloc phy regs
val deallocReqs = Input(Vec(CommitWidth, Bool())) val deallocReqs = Input(Vec(CommitWidth, Bool()))
...@@ -99,11 +99,12 @@ class FreeList extends XSModule with HasFreeListConsts with HasCircularQueuePtrH ...@@ -99,11 +99,12 @@ class FreeList extends XSModule with HasFreeListConsts with HasCircularQueuePtrH
val headPtrNext = Mux(io.req.canAlloc && io.req.doAlloc, headPtrAllocate, headPtr) val headPtrNext = Mux(io.req.canAlloc && io.req.doAlloc, headPtrAllocate, headPtr)
freeRegs := distanceBetween(tailPtr, headPtrNext) freeRegs := distanceBetween(tailPtr, headPtrNext)
// when mispredict or exception happens, reset headPtr to tailPtr (freelist is full). // priority: (1) exception and flushPipe; (2) walking; (3) mis-prediction; (4) normal dequeue
val resetHeadPtr = io.redirect.valid && (io.redirect.bits.isException || io.redirect.bits.isFlushPipe) headPtr := Mux(io.redirect.valid && io.redirect.bits.isUnconditional(),
headPtr := Mux(resetHeadPtr,
FreeListPtr(!tailPtrNext.flag, tailPtrNext.value), FreeListPtr(!tailPtrNext.flag, tailPtrNext.value),
Mux(io.walk.valid, headPtr - io.walk.bits, headPtrNext) Mux(io.walk.valid,
headPtr - io.walk.bits,
Mux(io.redirect.valid, headPtr, headPtrNext))
) )
XSDebug(p"head:$headPtr tail:$tailPtr\n") XSDebug(p"head:$headPtr tail:$tailPtr\n")
...@@ -111,10 +112,10 @@ class FreeList extends XSModule with HasFreeListConsts with HasCircularQueuePtrH ...@@ -111,10 +112,10 @@ class FreeList extends XSModule with HasFreeListConsts with HasCircularQueuePtrH
XSDebug(io.redirect.valid, p"redirect: brqIdx=${io.redirect.bits.brTag.value}\n") XSDebug(io.redirect.valid, p"redirect: brqIdx=${io.redirect.bits.brTag.value}\n")
val enableFreelistCheck = false val enableFreelistCheck = false
if(env.EnableDebug && enableFreelistCheck){ if (enableFreelistCheck) {
for( i <- 0 until FL_SIZE){ for (i <- 0 until FL_SIZE) {
for(j <- i+1 until FL_SIZE){ for (j <- i+1 until FL_SIZE) {
assert(freeList(i) != freeList(j), s"Found same entry in freelist! (i=$i j=$j)") XSError(freeList(i) === freeList(j), s"Found same entry in freelist! (i=$i j=$j)")
} }
} }
} }
......
...@@ -15,7 +15,7 @@ class RenameBypassInfo extends XSBundle { ...@@ -15,7 +15,7 @@ class RenameBypassInfo extends XSBundle {
class Rename extends XSModule { class Rename extends XSModule {
val io = IO(new Bundle() { val io = IO(new Bundle() {
val redirect = Flipped(ValidIO(new Redirect)) val redirect = Flipped(ValidIO(new Redirect))
val roqCommits = Vec(CommitWidth, Flipped(ValidIO(new RoqCommit))) val roqCommits = Flipped(new RoqCommitIO)
// from decode buffer // from decode buffer
val in = Vec(RenameWidth, Flipped(DecoupledIO(new CfCtrl))) val in = Vec(RenameWidth, Flipped(DecoupledIO(new CfCtrl)))
// to dispatch1 // to dispatch1
...@@ -40,28 +40,33 @@ class Rename extends XSModule { ...@@ -40,28 +40,33 @@ class Rename extends XSModule {
printRenameInfo(x, y) printRenameInfo(x, y)
} }
val fpFreeList, intFreeList = Module(new FreeList).io val intFreeList, fpFreeList = Module(new FreeList).io
val fpRat = Module(new RenameTable(float = true)).io
val intRat = Module(new RenameTable(float = false)).io val intRat = Module(new RenameTable(float = false)).io
val fpRat = Module(new RenameTable(float = true)).io
val allPhyResource = Seq((intRat, intFreeList, false), (fpRat, fpFreeList, true))
fpFreeList.redirect := io.redirect allPhyResource.map{ case (rat, freelist, _) =>
intFreeList.redirect := io.redirect rat.redirect := io.redirect
rat.walkWen := io.roqCommits.isWalk
val flush = io.redirect.valid && (io.redirect.bits.isException || io.redirect.bits.isFlushPipe) // TODO: need check by JiaWei freelist.redirect := io.redirect
fpRat.flush := flush freelist.walk.valid := io.roqCommits.isWalk
intRat.flush := flush }
def needDestReg[T <: CfCtrl](fp: Boolean, x: T): Bool = { def needDestReg[T <: CfCtrl](fp: Boolean, x: T): Bool = {
{if(fp) x.ctrl.fpWen else x.ctrl.rfWen && (x.ctrl.ldest =/= 0.U)} {if(fp) x.ctrl.fpWen else x.ctrl.rfWen && (x.ctrl.ldest =/= 0.U)}
} }
val walkValid = Cat(io.roqCommits.map(_.valid)).orR && io.roqCommits(0).bits.isWalk def needDestRegCommit[T <: RoqCommitInfo](fp: Boolean, x: T): Bool = {
fpFreeList.walk.valid := walkValid {if(fp) x.fpWen else x.rfWen && (x.ldest =/= 0.U)}
intFreeList.walk.valid := walkValid }
fpFreeList.walk.bits := PopCount(io.roqCommits.map(c => c.valid && needDestReg(true, c.bits.uop))) fpFreeList.walk.bits := PopCount(io.roqCommits.valid.zip(io.roqCommits.info).map{case (v, i) => v && needDestRegCommit(true, i)})
intFreeList.walk.bits := PopCount(io.roqCommits.map(c => c.valid && needDestReg(false, c.bits.uop))) intFreeList.walk.bits := PopCount(io.roqCommits.valid.zip(io.roqCommits.info).map{case (v, i) => v && needDestRegCommit(false, i)})
// walk has higher priority than allocation and thus we don't use isWalk here
fpFreeList.req.doAlloc := intFreeList.req.canAlloc && io.out(0).ready fpFreeList.req.doAlloc := intFreeList.req.canAlloc && io.out(0).ready
intFreeList.req.doAlloc := fpFreeList.req.canAlloc && io.out(0).ready intFreeList.req.doAlloc := fpFreeList.req.canAlloc && io.out(0).ready
/**
* Rename: allocate free physical register and update rename table
*/
val uops = Wire(Vec(RenameWidth, new MicroOp)) val uops = Wire(Vec(RenameWidth, new MicroOp))
uops.foreach( uop => { uops.foreach( uop => {
...@@ -79,7 +84,9 @@ class Rename extends XSModule { ...@@ -79,7 +84,9 @@ class Rename extends XSModule {
val needFpDest = Wire(Vec(RenameWidth, Bool())) val needFpDest = Wire(Vec(RenameWidth, Bool()))
val needIntDest = Wire(Vec(RenameWidth, Bool())) val needIntDest = Wire(Vec(RenameWidth, Bool()))
for(i <- 0 until RenameWidth) { val hasValid = Cat(io.in.map(_.valid)).orR
val canOut = io.out(0).ready && fpFreeList.req.canAlloc && intFreeList.req.canAlloc && !io.roqCommits.isWalk
for (i <- 0 until RenameWidth) {
uops(i).cf := io.in(i).bits.cf uops(i).cf := io.in(i).bits.cf
uops(i).ctrl := io.in(i).bits.ctrl uops(i).ctrl := io.in(i).bits.ctrl
uops(i).brTag := io.in(i).bits.brTag uops(i).brTag := io.in(i).bits.brTag
...@@ -92,7 +99,7 @@ class Rename extends XSModule { ...@@ -92,7 +99,7 @@ class Rename extends XSModule {
fpFreeList.req.allocReqs(i) := needFpDest(i) fpFreeList.req.allocReqs(i) := needFpDest(i)
intFreeList.req.allocReqs(i) := needIntDest(i) intFreeList.req.allocReqs(i) := needIntDest(i)
io.in(i).ready := io.out(i).ready && fpFreeList.req.canAlloc && intFreeList.req.canAlloc io.in(i).ready := !hasValid || canOut
// do checkpoints when a branch inst come // do checkpoints when a branch inst come
// for(fl <- Seq(fpFreeList, intFreeList)){ // for(fl <- Seq(fpFreeList, intFreeList)){
...@@ -108,45 +115,20 @@ class Rename extends XSModule { ...@@ -108,45 +115,20 @@ class Rename extends XSModule {
) )
) )
io.out(i).valid := io.in(i).valid && intFreeList.req.canAlloc && fpFreeList.req.canAlloc io.out(i).valid := io.in(i).valid && intFreeList.req.canAlloc && fpFreeList.req.canAlloc && !io.roqCommits.isWalk
io.out(i).bits := uops(i) io.out(i).bits := uops(i)
// write rename table // write speculative rename table
def writeRat(fp: Boolean) = { allPhyResource.map{ case (rat, freelist, _) =>
val rat = if(fp) fpRat else intRat val specWen = freelist.req.allocReqs(i) && freelist.req.canAlloc && freelist.req.doAlloc && !io.roqCommits.isWalk
val freeList = if(fp) fpFreeList else intFreeList
// speculative inst write
val specWen = freeList.req.allocReqs(i) && freeList.req.canAlloc && freeList.req.doAlloc
// walk back write
val commitDestValid = io.roqCommits(i).valid && needDestReg(fp, io.roqCommits(i).bits.uop)
val walkWen = commitDestValid && io.roqCommits(i).bits.isWalk
rat.specWritePorts(i).wen := specWen || walkWen
rat.specWritePorts(i).addr := Mux(specWen, uops(i).ctrl.ldest, io.roqCommits(i).bits.uop.ctrl.ldest)
rat.specWritePorts(i).wdata := Mux(specWen, freeList.req.pdests(i), io.roqCommits(i).bits.uop.old_pdest)
XSInfo(walkWen,
{if(fp) p"fp" else p"int "} + p"walk: pc:${Hexadecimal(io.roqCommits(i).bits.uop.cf.pc)}" +
p" ldest:${rat.specWritePorts(i).addr} old_pdest:${rat.specWritePorts(i).wdata}\n"
)
rat.archWritePorts(i).wen := commitDestValid && !io.roqCommits(i).bits.isWalk
rat.archWritePorts(i).addr := io.roqCommits(i).bits.uop.ctrl.ldest
rat.archWritePorts(i).wdata := io.roqCommits(i).bits.uop.pdest
XSInfo(rat.archWritePorts(i).wen,
{if(fp) p"fp" else p"int "} + p" rat arch: ldest:${rat.archWritePorts(i).addr}" +
p" pdest:${rat.archWritePorts(i).wdata}\n"
)
freeList.deallocReqs(i) := rat.archWritePorts(i).wen rat.specWritePorts(i).wen := specWen
freeList.deallocPregs(i) := io.roqCommits(i).bits.uop.old_pdest rat.specWritePorts(i).addr := uops(i).ctrl.ldest
rat.specWritePorts(i).wdata := freelist.req.pdests(i)
freelist.deallocReqs(i) := specWen
} }
writeRat(fp = false)
writeRat(fp = true)
// read rename table // read rename table
def readRat(lsrcList: List[UInt], ldest: UInt, fp: Boolean) = { def readRat(lsrcList: List[UInt], ldest: UInt, fp: Boolean) = {
val rat = if(fp) fpRat else intRat val rat = if(fp) fpRat else intRat
...@@ -199,4 +181,42 @@ class Rename extends XSModule { ...@@ -199,4 +181,42 @@ class Rename extends XSModule {
(fpMatch || intMatch) && io.in(j).bits.ctrl.ldest === io.in(i).bits.ctrl.ldest (fpMatch || intMatch) && io.in(j).bits.ctrl.ldest === io.in(i).bits.ctrl.ldest
}).reverse) }).reverse)
} }
/**
* Instructions commit: update freelist and rename table
*/
for (i <- 0 until CommitWidth) {
if (i >= RenameWidth) {
allPhyResource.map{ case (rat, _, _) =>
rat.specWritePorts(i).wen := false.B
rat.specWritePorts(i).addr := DontCare
rat.specWritePorts(i).wdata := DontCare
}
}
allPhyResource.map{ case (rat, freelist, fp) =>
// walk back write
val commitDestValid = io.roqCommits.valid(i) && needDestRegCommit(fp, io.roqCommits.info(i))
when (commitDestValid && io.roqCommits.isWalk) {
rat.specWritePorts(i).wen := true.B
rat.specWritePorts(i).addr := io.roqCommits.info(i).ldest
rat.specWritePorts(i).wdata := io.roqCommits.info(i).old_pdest
XSInfo({if(fp) p"fp" else p"int "} + p"walk: " +
p" ldest:${rat.specWritePorts(i).addr} old_pdest:${rat.specWritePorts(i).wdata}\n")
}
rat.archWritePorts(i).wen := commitDestValid && !io.roqCommits.isWalk
rat.archWritePorts(i).addr := io.roqCommits.info(i).ldest
rat.archWritePorts(i).wdata := io.roqCommits.info(i).pdest
XSInfo(rat.archWritePorts(i).wen,
{if(fp) p"fp" else p"int "} + p" rat arch: ldest:${rat.archWritePorts(i).addr}" +
p" pdest:${rat.archWritePorts(i).wdata}\n"
)
freelist.deallocReqs(i) := rat.archWritePorts(i).wen
freelist.deallocPregs(i) := io.roqCommits.info(i).old_pdest
}
}
} }
...@@ -17,9 +17,10 @@ class RatWritePort extends XSBundle { ...@@ -17,9 +17,10 @@ class RatWritePort extends XSBundle {
class RenameTable(float: Boolean) extends XSModule { class RenameTable(float: Boolean) extends XSModule {
val io = IO(new Bundle() { val io = IO(new Bundle() {
val flush = Input(Bool()) val redirect = Flipped(ValidIO(new Redirect))
val walkWen = Input(Bool())
val readPorts = Vec({if(float) 4 else 3} * RenameWidth, new RatReadPort) val readPorts = Vec({if(float) 4 else 3} * RenameWidth, new RatReadPort)
val specWritePorts = Vec(RenameWidth, new RatWritePort) val specWritePorts = Vec(CommitWidth, new RatWritePort)
val archWritePorts = Vec(CommitWidth, new RatWritePort) val archWritePorts = Vec(CommitWidth, new RatWritePort)
}) })
...@@ -29,8 +30,12 @@ class RenameTable(float: Boolean) extends XSModule { ...@@ -29,8 +30,12 @@ class RenameTable(float: Boolean) extends XSModule {
// arch state rename table // arch state rename table
val arch_table = RegInit(VecInit(Seq.tabulate(32)(i => i.U(PhyRegIdxWidth.W)))) val arch_table = RegInit(VecInit(Seq.tabulate(32)(i => i.U(PhyRegIdxWidth.W))))
// When redirect happens (mis-prediction), don't update the rename table
// However, when mis-prediction and walk happens at the same time, rename table needs to be updated
for(w <- io.specWritePorts){ for(w <- io.specWritePorts){
when(w.wen){ spec_table(w.addr) := w.wdata } when(w.wen && (!io.redirect.valid || io.walkWen)) {
spec_table(w.addr) := w.wdata
}
} }
for((r, i) <- io.readPorts.zipWithIndex){ for((r, i) <- io.readPorts.zipWithIndex){
...@@ -44,9 +49,11 @@ class RenameTable(float: Boolean) extends XSModule { ...@@ -44,9 +49,11 @@ class RenameTable(float: Boolean) extends XSModule {
when(w.wen){ arch_table(w.addr) := w.wdata } when(w.wen){ arch_table(w.addr) := w.wdata }
} }
when(io.flush){ val flush = io.redirect.valid && io.redirect.bits.isUnconditional()
when (flush) {
spec_table := arch_table spec_table := arch_table
for(w <- io.archWritePorts) { // spec table needs to be updated when flushPipe
for (w <- io.archWritePorts) {
when(w.wen){ spec_table(w.addr) := w.wdata } when(w.wen){ spec_table(w.addr) := w.wdata }
} }
} }
......
...@@ -117,7 +117,7 @@ class TlbEntry extends TlbBundle { ...@@ -117,7 +117,7 @@ class TlbEntry extends TlbBundle {
class TlbEntires(num: Int, tagLen: Int) extends TlbBundle { class TlbEntires(num: Int, tagLen: Int) extends TlbBundle {
require(log2Up(num)==log2Down(num)) require(log2Up(num)==log2Down(num))
/* vpn can be divide into three part */ /* vpn can be divide into three part */
// vpn: tagPart + addrPart // vpn: tagPart(17bit) + addrPart(8bit) + cutLenPart(2bit)
val cutLen = log2Up(num) val cutLen = log2Up(num)
val tag = UInt(tagLen.W) // NOTE: high part of vpn val tag = UInt(tagLen.W) // NOTE: high part of vpn
...@@ -127,9 +127,10 @@ class TlbEntires(num: Int, tagLen: Int) extends TlbBundle { ...@@ -127,9 +127,10 @@ class TlbEntires(num: Int, tagLen: Int) extends TlbBundle {
val vs = Vec(num, Bool()) val vs = Vec(num, Bool())
def tagClip(vpn: UInt, level: UInt) = { // full vpn => tagLen def tagClip(vpn: UInt, level: UInt) = { // full vpn => tagLen
Mux(level===0.U, Cat(vpn(vpnLen-1, vpnnLen*2+cutLen), 0.U(vpnnLen*2+cutLen)), val tmp = Mux(level===0.U, Cat(vpn(vpnLen-1, vpnnLen*2+cutLen), 0.U(vpnnLen*2)),
Mux(level===1.U, Cat(vpn(vpnLen-1, vpnnLen*1+cutLen), 0.U(vpnnLen*1+cutLen)), Mux(level===1.U, Cat(vpn(vpnLen-1, vpnnLen*1+cutLen), 0.U(vpnnLen*1)),
Cat(vpn(vpnLen-1, vpnnLen*0+cutLen), 0.U(vpnnLen*0+cutLen))))(tagLen-1, 0) Cat(vpn(vpnLen-1, vpnnLen*0+cutLen), 0.U(vpnnLen*0))))
tmp(tmp.getWidth-1, tmp.getWidth-tagLen)
} }
// NOTE: get insize idx // NOTE: get insize idx
...@@ -140,7 +141,7 @@ class TlbEntires(num: Int, tagLen: Int) extends TlbBundle { ...@@ -140,7 +141,7 @@ class TlbEntires(num: Int, tagLen: Int) extends TlbBundle {
} }
def hit(vpn: UInt) = { def hit(vpn: UInt) = {
(tag === tagClip(vpn, level)) && vs(idxClip(vpn, level)) (tag === tagClip(vpn, level)) && vs(idxClip(vpn, level)) && (level === 2.U)
} }
def genEntries(data: UInt, level: UInt, vpn: UInt): TlbEntires = { def genEntries(data: UInt, level: UInt, vpn: UInt): TlbEntires = {
...@@ -273,65 +274,105 @@ class TLB(Width: Int, isDtlb: Boolean) extends TlbModule with HasCSRConst{ ...@@ -273,65 +274,105 @@ class TLB(Width: Int, isDtlb: Boolean) extends TlbModule with HasCSRConst{
val entry = Reg(Vec(TlbEntrySize, new TlbEntry)) val entry = Reg(Vec(TlbEntrySize, new TlbEntry))
val g = VecInit(entry.map(_.perm.g)).asUInt // TODO: need check if reverse is needed val g = VecInit(entry.map(_.perm.g)).asUInt // TODO: need check if reverse is needed
val entryHitVec = widthMapSeq{i => VecInit(entry.map(_.hit(reqAddr(i).vpn/*, satp.asid*/))) } /**
val hitVec = widthMapSeq{ i => (v.asBools zip entryHitVec(i)).map{ case (a,b) => a&b } } * PTW refill
val pfHitVec = widthMapSeq{ i => (pf.asBools zip entryHitVec(i)).map{ case (a,b) => a&b } } */
val pfArray = widthMap{ i => ParallelOR(pfHitVec(i)).asBool && valid(i) && vmEnable } val refill = ptw.resp.fire()
val hit = widthMap{ i => ParallelOR(hitVec(i)).asBool && valid(i) && vmEnable && ~pfArray(i) } val randIdx = LFSR64()(log2Up(TlbEntrySize)-1,0)
val miss = widthMap{ i => !hit(i) && valid(i) && vmEnable && ~pfArray(i) } val priorIdx = PriorityEncoder(~(v|pf))
val hitppn = widthMap{ i => ParallelMux(hitVec(i) zip entry.map(_.ppn)) } val tlbfull = ParallelAND((v|pf).asBools)
val hitPerm = widthMap{ i => ParallelMux(hitVec(i) zip entry.map(_.perm)) } val refillIdx = Mux(tlbfull, randIdx, priorIdx)
val hitLevel= widthMap{ i => ParallelMux(hitVec(i) zip entry.map(_.level)) } val refillIdxOH = UIntToOH(refillIdx)
val multiHit = { when (refill) {
val hitSum = widthMap{ i => PopCount(hitVec(i)) } v := Mux(ptw.resp.bits.pf, v & ~refillIdxOH, v | refillIdxOH)
val pfHitSum = widthMap{ i => PopCount(pfHitVec(i)) } entry(refillIdx) := ptw.resp.bits.entry
ParallelOR(widthMap{ i => !(hitSum(i)===0.U || hitSum(i)===1.U) || !(pfHitSum(i)===0.U || pfHitSum(i)===1.U)}) XSDebug(p"Refill: idx:${refillIdx} entry:${ptw.resp.bits.entry}\n")
} }
// resp // TODO: A/D has not being concerned /**
for(i <- 0 until Width) { * L1 TLB read
val paddr = LookupTreeDefault(hitLevel(i), Cat(hitppn(i), reqAddr(i).off), List( */
0.U -> Cat(hitppn(i)(ppnLen - 1, 2*vpnnLen), reqAddr(i).vpn(2*vpnnLen - 1, 0), reqAddr(i).off), val tlb_read_mask = Mux(refill, refillIdxOH, 0.U(TlbEntrySize.W))
1.U -> Cat(hitppn(i)(ppnLen - 1, vpnnLen), reqAddr(i).vpn(vpnnLen - 1, 0), reqAddr(i).off), def TLBRead(i: Int) = {
2.U -> Cat(hitppn(i), reqAddr(i).off) val entryHitVec = (
if (isDtlb)
VecInit((tlb_read_mask.asBools zip entry).map{ case (r, e) => !r && e.hit(reqAddr(i).vpn/*, satp.asid*/)})
else
VecInit(entry.map(_.hit(reqAddr(i).vpn/*, satp.asid*/)))
)
val reqAddrReg = if (isDtlb) RegNext(reqAddr(i)) else reqAddr(i)
val cmdReg = if (isDtlb) RegNext(cmd(i)) else cmd(i)
val validReg = if (isDtlb) RegNext(valid(i)) else valid(i)
val entryHitVecReg = if (isDtlb) RegNext(entryHitVec) else entryHitVec
val hitVec = (v.asBools zip entryHitVecReg).map{ case (a,b) => a&b }
val pfHitVec = (pf.asBools zip entryHitVecReg).map{ case (a,b) => a&b }
val pfArray = ParallelOR(pfHitVec).asBool && validReg && vmEnable
val hit = ParallelOR(hitVec).asBool && validReg && vmEnable && ~pfArray
val miss = !hit && validReg && vmEnable && ~pfArray
val hitppn = ParallelMux(hitVec zip entry.map(_.ppn))
val hitPerm = ParallelMux(hitVec zip entry.map(_.perm))
val hitLevel= ParallelMux(hitVec zip entry.map(_.level))
val multiHit = {
val hitSum = PopCount(hitVec)
val pfHitSum = PopCount(pfHitVec)
!(hitSum===0.U || hitSum===1.U) || !(pfHitSum===0.U || pfHitSum===1.U)
}
// resp // TODO: A/D has not being concerned
val paddr = LookupTreeDefault(hitLevel, Cat(hitppn, reqAddrReg.off), List(
0.U -> Cat(hitppn(ppnLen - 1, 2*vpnnLen), reqAddrReg.vpn(2*vpnnLen - 1, 0), reqAddrReg.off),
1.U -> Cat(hitppn(ppnLen - 1, vpnnLen), reqAddrReg.vpn(vpnnLen - 1, 0), reqAddrReg.off),
2.U -> Cat(hitppn, reqAddrReg.off)
)) ))
val vaddr = SignExt(req(i).bits.vaddr, PAddrBits)
req(i).ready := resp(i).ready req(i).ready := resp(i).ready
resp(i).valid := valid(i) resp(i).valid := validReg
resp(i).bits.paddr := Mux(vmEnable, paddr, SignExt(req(i).bits.vaddr, PAddrBits)) resp(i).bits.paddr := Mux(vmEnable, paddr, if (isDtlb) RegNext(vaddr) else vaddr)
resp(i).bits.miss := miss(i) resp(i).bits.miss := miss
val perm = hitPerm(i) // NOTE: given the excp, the out module choose one to use? val perm = hitPerm // NOTE: given the excp, the out module choose one to use?
val update = false.B && hit(i) && (!hitPerm(i).a || !hitPerm(i).d && TlbCmd.isWrite(cmd(i))) // update A/D through exception val update = false.B && hit && (!hitPerm.a || !hitPerm.d && TlbCmd.isWrite(cmdReg)) // update A/D through exception
val modeCheck = !(mode === ModeU && !perm.u || mode === ModeS && perm.u && (!priv.sum || ifecth)) val modeCheck = !(mode === ModeU && !perm.u || mode === ModeS && perm.u && (!priv.sum || ifecth))
val ldPf = (pfArray(i) && TlbCmd.isRead(cmd(i)) && true.B /*!isAMO*/) || hit(i) && !(modeCheck && (perm.r || priv.mxr && perm.x)) && (TlbCmd.isRead(cmd(i)) && true.B/*!isAMO*/) // TODO: handle isAMO val ldPf = (pfArray && TlbCmd.isRead(cmdReg) && true.B /*!isAMO*/) || hit && !(modeCheck && (perm.r || priv.mxr && perm.x)) && (TlbCmd.isRead(cmdReg) && true.B/*!isAMO*/) // TODO: handle isAMO
val stPf = (pfArray(i) && TlbCmd.isWrite(cmd(i)) || false.B /*isAMO*/ ) || hit(i) && !(modeCheck && perm.w) && (TlbCmd.isWrite(cmd(i)) || false.B/*TODO isAMO. */) val stPf = (pfArray && TlbCmd.isWrite(cmdReg) || false.B /*isAMO*/ ) || hit && !(modeCheck && perm.w) && (TlbCmd.isWrite(cmdReg) || false.B/*TODO isAMO. */)
val instrPf = (pfArray(i) && TlbCmd.isExec(cmd(i))) || hit(i) && !(modeCheck && perm.x) && TlbCmd.isExec(cmd(i)) val instrPf = (pfArray && TlbCmd.isExec(cmdReg)) || hit && !(modeCheck && perm.x) && TlbCmd.isExec(cmdReg)
resp(i).bits.excp.pf.ld := ldPf || update resp(i).bits.excp.pf.ld := ldPf || update
resp(i).bits.excp.pf.st := stPf || update resp(i).bits.excp.pf.st := stPf || update
resp(i).bits.excp.pf.instr := instrPf || update resp(i).bits.excp.pf.instr := instrPf || update
(hit, miss, pfHitVec, multiHit)
} }
val readResult = (0 until Width).map(TLBRead(_))
val hitVec = readResult.map(res => res._1)
val missVec = readResult.map(res => res._2)
val pfHitVecVec = readResult.map(res => res._3)
val multiHitVec = readResult.map(res => res._4)
val hasMissReq = Cat(missVec).orR
// ptw // ptw
val state_idle :: state_wait :: Nil = Enum(2) val state_idle :: state_wait :: Nil = Enum(2)
val state = RegInit(state_idle) val state = RegInit(state_idle)
ptw <> DontCare // TODO: need check it ptw <> DontCare // TODO: need check it
ptw.req.valid := ParallelOR(miss).asBool && state===state_idle && !sfence.valid ptw.req.valid := hasMissReq && state===state_idle && !sfence.valid
ptw.resp.ready := state===state_wait ptw.resp.ready := state===state_wait
// val ptwReqSeq = Wire(Seq.fill(Width)(new comBundle())) // val ptwReqSeq = Wire(Seq.fill(Width)(new comBundle()))
val ptwReqSeq = Seq.fill(Width)(Wire(new comBundle())) val ptwReqSeq = Seq.fill(Width)(Wire(new comBundle()))
for (i <- 0 until Width) { for (i <- 0 until Width) {
ptwReqSeq(i).valid := valid(i) && miss(i) ptwReqSeq(i).valid := ((if (isDtlb) RegNext(valid(i)) else valid(i)) && missVec(i))
ptwReqSeq(i).roqIdx := req(i).bits.roqIdx ptwReqSeq(i).roqIdx := (if (isDtlb) RegNext(req(i).bits.roqIdx) else req(i).bits.roqIdx)
ptwReqSeq(i).bits.vpn := reqAddr(i).vpn ptwReqSeq(i).bits.vpn := (if (isDtlb) RegNext(reqAddr(i).vpn) else reqAddr(i).vpn)
} }
ptw.req.bits := Compare(ptwReqSeq).bits ptw.req.bits := Compare(ptwReqSeq).bits
switch (state) { switch (state) {
is (state_idle) { is (state_idle) {
when (ParallelOR(miss).asBool && ptw.req.fire()) { when (hasMissReq && ptw.req.fire()) {
state := state_wait state := state_wait
} }
assert(!ptw.resp.valid) assert(!ptw.resp.valid)
...@@ -345,28 +386,15 @@ class TLB(Width: Int, isDtlb: Boolean) extends TlbModule with HasCSRConst{ ...@@ -345,28 +386,15 @@ class TLB(Width: Int, isDtlb: Boolean) extends TlbModule with HasCSRConst{
} }
// reset pf when pf hit // reset pf when pf hit
val pfHitReset = ParallelOR(widthMap{i => Mux(resp(i).fire(), VecInit(pfHitVec(i)).asUInt, 0.U) }) val pfHitReset = ParallelOR(widthMap{i => Mux(resp(i).fire(), VecInit(pfHitVecVec(i)).asUInt, 0.U) })
val pfHitRefill = ParallelOR(pfHitReset.asBools) val pfHitRefill = false.B//ParallelOR(pfHitReset.asBools)
// refill
val refill = ptw.resp.fire()
val randIdx = LFSR64()(log2Up(TlbEntrySize)-1,0)
val priorIdx = PriorityEncoder(~(v|pf))
val tlbfull = ParallelAND((v|pf).asBools)
val refillIdx = Mux(tlbfull, randIdx, priorIdx)
val re2OH = UIntToOH(refillIdx)
when (refill) {
v := Mux(ptw.resp.bits.pf, v & ~re2OH, v | re2OH)
entry(refillIdx) := ptw.resp.bits.entry
XSDebug(p"Refill: idx:${refillIdx} entry:${ptw.resp.bits.entry}\n")
}
// pf update // pf update
when (refill) { when (refill) {
when (pfHitRefill) { when (pfHitRefill) {
pf := Mux(ptw.resp.bits.pf, pf | re2OH, pf & ~re2OH) & ~pfHitReset pf := Mux(ptw.resp.bits.pf, pf | refillIdxOH, pf & ~refillIdxOH) & ~pfHitReset
} .otherwise { } .otherwise {
pf := Mux(ptw.resp.bits.pf, pf | re2OH, pf & ~re2OH) pf := Mux(ptw.resp.bits.pf, pf | refillIdxOH, pf & ~refillIdxOH)
} }
} .otherwise { } .otherwise {
when (pfHitRefill) { when (pfHitRefill) {
...@@ -374,7 +402,7 @@ class TLB(Width: Int, isDtlb: Boolean) extends TlbModule with HasCSRConst{ ...@@ -374,7 +402,7 @@ class TLB(Width: Int, isDtlb: Boolean) extends TlbModule with HasCSRConst{
} }
} }
when (PopCount(pf) > 10.U) { // when too much pf, just clear when (PopCount(pf) > 10.U) { // when too much pf, just clear
pf := Mux(refill && ptw.resp.bits.pf, re2OH, 0.U) pf := Mux(refill && ptw.resp.bits.pf, refillIdxOH, 0.U)
} }
// sfence (flush) // sfence (flush)
...@@ -409,15 +437,15 @@ class TLB(Width: Int, isDtlb: Boolean) extends TlbModule with HasCSRConst{ ...@@ -409,15 +437,15 @@ class TLB(Width: Int, isDtlb: Boolean) extends TlbModule with HasCSRConst{
ExcitingUtils.addSource(valid(1)/* && vmEnable*/, "perfCntDtlbReqCnt1", Perf) ExcitingUtils.addSource(valid(1)/* && vmEnable*/, "perfCntDtlbReqCnt1", Perf)
ExcitingUtils.addSource(valid(2)/* && vmEnable*/, "perfCntDtlbReqCnt2", Perf) ExcitingUtils.addSource(valid(2)/* && vmEnable*/, "perfCntDtlbReqCnt2", Perf)
ExcitingUtils.addSource(valid(3)/* && vmEnable*/, "perfCntDtlbReqCnt3", Perf) ExcitingUtils.addSource(valid(3)/* && vmEnable*/, "perfCntDtlbReqCnt3", Perf)
ExcitingUtils.addSource(valid(0)/* && vmEnable*/ && miss(0), "perfCntDtlbMissCnt0", Perf) ExcitingUtils.addSource(valid(0)/* && vmEnable*/ && missVec(0), "perfCntDtlbMissCnt0", Perf)
ExcitingUtils.addSource(valid(1)/* && vmEnable*/ && miss(1), "perfCntDtlbMissCnt1", Perf) ExcitingUtils.addSource(valid(1)/* && vmEnable*/ && missVec(1), "perfCntDtlbMissCnt1", Perf)
ExcitingUtils.addSource(valid(2)/* && vmEnable*/ && miss(2), "perfCntDtlbMissCnt2", Perf) ExcitingUtils.addSource(valid(2)/* && vmEnable*/ && missVec(2), "perfCntDtlbMissCnt2", Perf)
ExcitingUtils.addSource(valid(3)/* && vmEnable*/ && miss(3), "perfCntDtlbMissCnt3", Perf) ExcitingUtils.addSource(valid(3)/* && vmEnable*/ && missVec(3), "perfCntDtlbMissCnt3", Perf)
} }
if (!env.FPGAPlatform && !isDtlb) { if (!env.FPGAPlatform && !isDtlb) {
ExcitingUtils.addSource(valid(0)/* && vmEnable*/, "perfCntItlbReqCnt0", Perf) ExcitingUtils.addSource(valid(0)/* && vmEnable*/, "perfCntItlbReqCnt0", Perf)
ExcitingUtils.addSource(valid(0)/* && vmEnable*/ && miss(0), "perfCntItlbMissCnt0", Perf) ExcitingUtils.addSource(valid(0)/* && vmEnable*/ && missVec(0), "perfCntItlbMissCnt0", Perf)
} }
// Log // Log
...@@ -428,7 +456,7 @@ class TLB(Width: Int, isDtlb: Boolean) extends TlbModule with HasCSRConst{ ...@@ -428,7 +456,7 @@ class TLB(Width: Int, isDtlb: Boolean) extends TlbModule with HasCSRConst{
XSDebug(sfence.valid, p"Sfence: ${sfence}\n") XSDebug(sfence.valid, p"Sfence: ${sfence}\n")
XSDebug(ParallelOR(valid)|| ptw.resp.valid, p"CSR: ${csr}\n") XSDebug(ParallelOR(valid)|| ptw.resp.valid, p"CSR: ${csr}\n")
XSDebug(ParallelOR(valid) || ptw.resp.valid, p"vmEnable:${vmEnable} hit:${Binary(VecInit(hit).asUInt)} miss:${Binary(VecInit(miss).asUInt)} v:${Hexadecimal(v)} pf:${Hexadecimal(pf)} state:${state}\n") XSDebug(ParallelOR(valid) || ptw.resp.valid, p"vmEnable:${vmEnable} hit:${Binary(VecInit(hitVec).asUInt)} miss:${Binary(VecInit(missVec).asUInt)} v:${Hexadecimal(v)} pf:${Hexadecimal(pf)} state:${state}\n")
XSDebug(ptw.req.fire(), p"PTW req:${ptw.req.bits}\n") XSDebug(ptw.req.fire(), p"PTW req:${ptw.req.bits}\n")
XSDebug(ptw.resp.valid, p"PTW resp:${ptw.resp.bits} (v:${ptw.resp.valid}r:${ptw.resp.ready}) \n") XSDebug(ptw.resp.valid, p"PTW resp:${ptw.resp.bits} (v:${ptw.resp.valid}r:${ptw.resp.ready}) \n")
...@@ -437,7 +465,7 @@ class TLB(Width: Int, isDtlb: Boolean) extends TlbModule with HasCSRConst{ ...@@ -437,7 +465,7 @@ class TLB(Width: Int, isDtlb: Boolean) extends TlbModule with HasCSRConst{
// assert((hit(i)&pfArray(i))===false.B, "hit(%d):%d pfArray(%d):%d v:0x%x pf:0x%x", i.U, hit(i), i.U, pfArray(i), v, pf) // assert((hit(i)&pfArray(i))===false.B, "hit(%d):%d pfArray(%d):%d v:0x%x pf:0x%x", i.U, hit(i), i.U, pfArray(i), v, pf)
// } // }
// for(i <- 0 until Width) { // for(i <- 0 until Width) {
// XSDebug(multiHit, p"vpn:0x${Hexadecimal(reqAddr(i).vpn)} hitVec:0x${Hexadecimal(VecInit(hitVec(i)).asUInt)} pfHitVec:0x${Hexadecimal(VecInit(pfHitVec(i)).asUInt)}\n") // XSDebug(multiHit, p"vpn:0x${Hexadecimal(reqAddr(i).vpn)} hitVec:0x${Hexadecimal(VecInit(hitVec(i)).asUInt)} pfHitVecVec:0x${Hexadecimal(VecInit(pfHitVecVec(i)).asUInt)}\n")
// } // }
// for(i <- 0 until TlbEntrySize) { // for(i <- 0 until TlbEntrySize) {
// XSDebug(multiHit, p"entry(${i.U}): v:${v(i)} ${entry(i)}\n") // XSDebug(multiHit, p"entry(${i.U}): v:${v(i)} ${entry(i)}\n")
...@@ -500,4 +528,4 @@ object TLB { ...@@ -500,4 +528,4 @@ object TLB {
tlb.io.ptw tlb.io.ptw
} }
} }
\ No newline at end of file
...@@ -128,7 +128,7 @@ class LoadPipe extends DCacheModule ...@@ -128,7 +128,7 @@ class LoadPipe extends DCacheModule
val s2_data_word = s2_data_words(s2_word_idx) val s2_data_word = s2_data_words(s2_word_idx)
val s2_decoded = cacheParams.dataCode.decode(s2_data_word) val s2_decoded = cacheParams.dataCode.decode(s2_data_word)
val s2_data_word_decoded = s2_decoded.corrected val s2_data_word_decoded = s2_decoded.corrected
assert(!(s2_valid && s2_hit && !s2_nack && s2_decoded.uncorrectable)) // assert(!(s2_valid && s2_hit && !s2_nack && s2_decoded.uncorrectable))
val resp = Wire(ValidIO(new DCacheWordResp)) val resp = Wire(ValidIO(new DCacheWordResp))
......
...@@ -455,7 +455,7 @@ class PTWImp(outer: PTW) extends PtwModule(outer){ ...@@ -455,7 +455,7 @@ class PTWImp(outer: PTW) extends PtwModule(outer){
l2g := (l2g & ~UIntToOH(refillIdx)) | Mux(Cat(memPtes.map(_.perm.g)).andR, UIntToOH(refillIdx), 0.U) l2g := (l2g & ~UIntToOH(refillIdx)) | Mux(Cat(memPtes.map(_.perm.g)).andR, UIntToOH(refillIdx), 0.U)
XSDebug(p"ptwl2 RefillIdx:${Hexadecimal(refillIdx)} ps:${ps}\n") XSDebug(p"ptwl2 RefillIdx:${Hexadecimal(refillIdx)} ps:${ps}\n")
} }
when (memPte.isLeaf()) { when (memPte.isLeaf() && (level===2.U)) {
val refillIdx = genTlbL2Idx(req.vpn)//getVpnn(req.vpn, 0)(log2Up(TlbL2EntrySize)-1, 0) val refillIdx = genTlbL2Idx(req.vpn)//getVpnn(req.vpn, 0)(log2Up(TlbL2EntrySize)-1, 0)
//TODO: check why the old refillIdx is right //TODO: check why the old refillIdx is right
...@@ -501,11 +501,11 @@ class PTWImp(outer: PTW) extends PtwModule(outer){ ...@@ -501,11 +501,11 @@ class PTWImp(outer: PTW) extends PtwModule(outer){
} .otherwise { } .otherwise {
when (sfence.bits.rs2) { when (sfence.bits.rs2) {
// specific leaf of addr && all asid // specific leaf of addr && all asid
tlbv := tlbv & ~UIntToOH(sfence.bits.addr(log2Up(TlbL2EntrySize)-1+offLen, 0+offLen)) tlbv := tlbv & ~UIntToOH(genTlbL2Idx(sfence.bits.addr(sfence.bits.addr.getWidth-1, offLen)))
tlbg := tlbg & ~UIntToOH(sfence.bits.addr(log2Up(TlbL2EntrySize)-1+offLen, 0+offLen)) tlbg := tlbg & ~UIntToOH(genTlbL2Idx(sfence.bits.addr(sfence.bits.addr.getWidth-1, offLen)))
} .otherwise { } .otherwise {
// specific leaf of addr && specific asid // specific leaf of addr && specific asid
tlbv := tlbv & (~UIntToOH(sfence.bits.addr(log2Up(TlbL2EntrySize)-1+offLen, 0+offLen)) | tlbg) tlbv := tlbv & (~UIntToOH(genTlbL2Idx(sfence.bits.addr(sfence.bits.addr.getWidth-1, offLen)))| tlbg)
} }
} }
} }
......
...@@ -9,10 +9,10 @@ import xiangshan.cache._ ...@@ -9,10 +9,10 @@ import xiangshan.cache._
class Frontend extends XSModule { class Frontend extends XSModule {
val io = IO(new Bundle() { val io = IO(new Bundle() {
val icacheReq = DecoupledIO(new ICacheReq) val icacheMemAcq = DecoupledIO(new L1plusCacheReq)
val icacheResp = Flipped(DecoupledIO(new ICacheResp)) val icacheMemGrant = Flipped(DecoupledIO(new L1plusCacheResp))
val icacheFlush = Output(UInt(2.W)) val l1plusFlush = Output(Bool())
val icacheToTlb = Flipped(new BlockTlbRequestIO) val fencei = Input(Bool())
val ptw = new TlbPtwIO val ptw = new TlbPtwIO
val backend = new FrontendToBackendIO val backend = new FrontendToBackendIO
val sfence = Input(new SfenceBundle) val sfence = Input(new SfenceBundle)
...@@ -21,30 +21,29 @@ class Frontend extends XSModule { ...@@ -21,30 +21,29 @@ class Frontend extends XSModule {
val ifu = Module(new IFU) val ifu = Module(new IFU)
val ibuffer = Module(new Ibuffer) val ibuffer = Module(new Ibuffer)
val needFlush = io.backend.redirect.valid val needFlush = io.backend.redirect.valid
//backend // from backend
ifu.io.redirect <> io.backend.redirect ifu.io.redirect <> io.backend.redirect
ifu.io.inOrderBrInfo <> io.backend.inOrderBrInfo ifu.io.cfiUpdateInfo <> io.backend.cfiUpdateInfo
ifu.io.outOfOrderBrInfo <> io.backend.outOfOrderBrInfo // to icache
//icache ifu.io.icacheMemGrant <> io.icacheMemGrant
io.icacheReq <> ifu.io.icacheReq ifu.io.fencei := io.fencei
io.icacheFlush <> ifu.io.icacheFlush // to tlb
ifu.io.icacheResp <> io.icacheResp ifu.io.sfence := io.sfence
//itlb to ptw ifu.io.tlbCsr := io.tlbCsr
io.ptw <> TLB( // from icache
in = Seq(io.icacheToTlb), io.l1plusFlush := ifu.io.l1plusFlush
sfence = io.sfence, io.icacheMemAcq <> ifu.io.icacheMemAcq
csr = io.tlbCsr, // itlb to ptw
width = 1, io.ptw <> ifu.io.ptw
isDtlb = false, // ifu to ibuffer
shouldBlock = true
)
//ibuffer
ibuffer.io.in <> ifu.io.fetchPacket ibuffer.io.in <> ifu.io.fetchPacket
// backend to ibuffer
ibuffer.io.flush := needFlush ibuffer.io.flush := needFlush
// ibuffer to backend
io.backend.cfVec <> ibuffer.io.out io.backend.cfVec <> ibuffer.io.out
// for(out <- ibuffer.io.out){ // for(out <- ibuffer.io.out){
......
...@@ -309,13 +309,13 @@ class LoopPredictor extends BasePredictor with LTBParams { ...@@ -309,13 +309,13 @@ class LoopPredictor extends BasePredictor with LTBParams {
ltbs(i).io.req.idx := Mux(isInNextRow(i), baseRow + 1.U, baseRow) ltbs(i).io.req.idx := Mux(isInNextRow(i), baseRow + 1.U, baseRow)
ltbs(i).io.req.tag := realTags(i) ltbs(i).io.req.tag := realTags(i)
// ltbs(i).io.outMask := outMask(i) // ltbs(i).io.outMask := outMask(i)
ltbs(i).io.update.valid := i.U === ltbAddr.getBank(io.update.bits.ui.pc) && io.update.valid && io.update.bits.ui.pd.isBr ltbs(i).io.update.valid := i.U === ltbAddr.getBank(io.update.bits.pc) && io.update.valid && io.update.bits.pd.isBr
ltbs(i).io.update.bits.misPred := io.update.bits.ui.isMisPred ltbs(i).io.update.bits.misPred := io.update.bits.isMisPred
ltbs(i).io.update.bits.pc := io.update.bits.ui.pc ltbs(i).io.update.bits.pc := io.update.bits.pc
ltbs(i).io.update.bits.meta := io.update.bits.ui.brInfo.specCnt ltbs(i).io.update.bits.meta := io.update.bits.bpuMeta.specCnt
ltbs(i).io.update.bits.taken := io.update.bits.ui.taken ltbs(i).io.update.bits.taken := io.update.bits.taken
ltbs(i).io.update.bits.brTag := io.update.bits.ui.brTag ltbs(i).io.update.bits.brTag := io.update.bits.brTag
ltbs(i).io.repair := i.U =/= ltbAddr.getBank(io.update.bits.ui.pc) && io.update.valid && io.update.bits.ui.isMisPred ltbs(i).io.repair := i.U =/= ltbAddr.getBank(io.update.bits.pc) && io.update.valid && io.update.bits.isMisPred
} }
val ltbResps = VecInit((0 until PredictWidth).map(i => ltbs(i).io.resp)) val ltbResps = VecInit((0 until PredictWidth).map(i => ltbs(i).io.resp))
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
import "DPI-C" function void xs_assert
(
input longint line
);
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册