提交 aa776945 编写于 作者: A Allen

Merge branch 'dev-lsu' of github.com:RISCVERS/XiangShan into dev-lsu

There are still compile errors.
......@@ -3,7 +3,7 @@ name: EMU Test
on:
push:
branches: [ master ]
branches: [ master, update-ci ]
pull_request:
branches: [ master ]
......@@ -18,7 +18,7 @@ jobs:
echo ::set-env name=NEMU_HOME::/home/ci-runner/xsenv/NEMU
echo ::set-env name=NOOP_HOME::$GITHUB_WORKSPACE
- name: Build EMU
run: make ./build/emu NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME -j20
run: make ./build/emu SIM_ARGS=--disable-log NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME -j20
cputest:
runs-on: self-hosted
......@@ -36,7 +36,38 @@ jobs:
echo $AM_HOME
echo $NEMU_HOME
echo $NOOP_HOME
make -C $AM_HOME/tests/cputest/ ARCH=riscv64-noop V=OFF AM_HOME=$AM_HOME NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME run
CPU_TEST_DIR=$AM_HOME/tests/cputest
echo $CPU_TEST_DIR
ret=0
for test in $(ls $CPU_TEST_DIR/tests)
do
t=${test%.c}
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"
if [[ $? == 1 ]];
then
echo $t fail
ret=1
fi
done
exit $ret
microbench:
runs-on: self-hosted
name: Run microbench
needs: [build-emu]
steps:
- name: Set env
run: |
echo ::set-env name=AM_HOME::/home/ci-runner/xsenv/nexus-am
echo ::set-env name=NEMU_HOME::/home/ci-runner/xsenv/NEMU
echo ::set-env name=NOOP_HOME::$GITHUB_WORKSPACE
- name: Run microbench
run: |
echo $AM_HOME
echo $NEMU_HOME
echo $NOOP_HOME
make -C $AM_HOME/apps/microbench ARCH=riscv64-noop AM_HOME=$AM_HOME NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME mainargs=test run
riscv-tests:
runs-on: self-hosted
......@@ -53,4 +84,4 @@ jobs:
echo $NEMU_HOME
echo $NOOP_HOME
echo $RVTEST_HOME
make -C $RVTEST_HOME/isa/ SUITES+=rv64ui SUITES+=rv64um V=OFF NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME noop_run
make -C $RVTEST_HOME/isa/ SUITES+=rv64ui SUITES+=rv64um NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME noop_run
......@@ -340,6 +340,10 @@ hs_err_pid*
# vscode environment
.vscode
.metals
.bloop
.coursier
mill.rdiB
stale_outputs_checked
......@@ -11,7 +11,8 @@ IMAGE ?= temp
# remote machine with high frequency to speedup verilog generation
REMOTE ?= localhost
REMOTE_PREFIX ?= /nfs/24/$(abspath .)/
REMOTE_PREFIX ?=
REMOTE_PRJ_HOME = $(REMOTE_PREFIX)/$(abspath .)/
.DEFAULT_GOAL = verilog
......@@ -43,12 +44,13 @@ verilog: $(TOP_V)
SIM_TOP = XSSimTop
SIM_TOP_V = $(BUILD_DIR)/$(SIM_TOP).v
SIM_ARGS =
$(SIM_TOP_V): $(SCALA_FILE) $(TEST_FILE)
mkdir -p $(@D)
ifeq ($(REMOTE),localhost)
mill chiselModule.test.runMain $(SIMTOP) -X verilog -td $(@D) --output-file $(@F)
mill chiselModule.test.runMain $(SIMTOP) -X verilog -td $(@D) --output-file $(@F) $(SIM_ARGS)
else
ssh $(REMOTE) "cd $(REMOTE_PREFIX) && mill chiselModule.test.runMain $(SIMTOP) -X verilog -td $(@D) --output-file $(@F)"
ssh -tt $(REMOTE) "cd $(REMOTE_PRJ_HOME) && mill chiselModule.test.runMain $(SIMTOP) -X verilog -td $(@D) --output-file $(@F) $(SIM_ARGS)"
endif
......@@ -57,17 +59,19 @@ EMU_VSRC_DIR = $(abspath ./src/test/vsrc)
EMU_CXXFILES = $(shell find $(EMU_CSRC_DIR) -name "*.cpp")
EMU_VFILES = $(shell find $(EMU_VSRC_DIR) -name "*.v" -or -name "*.sv")
EMU_CXXFLAGS = -O3 -std=c++11 -static -g -Wall -I$(EMU_CSRC_DIR)
EMU_CXXFLAGS = -std=c++11 -static -Wall -I$(EMU_CSRC_DIR)
EMU_CXXFLAGS += -DVERILATOR -Wno-maybe-uninitialized
EMU_LDFLAGS = -lpthread -lSDL2 -ldl
# dump vcd: --debug --trace
VERILATOR_FLAGS = --top-module $(SIM_TOP) \
+define+VERILATOR=1 \
+define+PRINTF_COND=1 \
+define+RANDOMIZE_REG_INIT \
+define+RANDOMIZE_MEM_INIT \
--assert \
--savable \
--stats-vars \
--trace \
--output-split 5000 \
--output-split-cfuncs 5000 \
-I$(abspath $(BUILD_DIR)) \
......@@ -94,22 +98,34 @@ $(REF_SO):
$(MAKE) -C $(NEMU_HOME) ISA=riscv64 SHARE=1
$(EMU): $(EMU_MK) $(EMU_DEPS) $(EMU_HEADERS) $(REF_SO)
CPPFLAGS=-DREF_SO=\\\"$(REF_SO)\\\" $(MAKE) VM_PARALLEL_BUILDS=1 -C $(dir $(EMU_MK)) -f $(abspath $(EMU_MK))
CPPFLAGS=-DREF_SO=\\\"$(REF_SO)\\\" time $(MAKE) VM_PARALLEL_BUILDS=1 OPT_FAST="-O3" -C $(dir $(EMU_MK)) -f $(abspath $(EMU_MK))
SEED = -s $(shell seq 1 10000 | shuf | head -n 1)
SEED ?= $(shell shuf -i 1-10000 -n 1)
# log will only be printed when (B<=GTimer<=E) && (L < loglevel)
# use 'emu -h' to see more details
B ?= 0
E ?= -1
V ?= ALL
SNAPSHOT ?=
# enable this runtime option if you want to generate a vcd file
# use 'emu -h' to see more details
#WAVEFORM = --dump-wave
ifeq ($(SNAPSHOT),)
SNAPSHOT_OPTION =
else
SNAPSHOT_OPTION = --load-snapshot=$(REMOTE_PREFIX)/$(SNAPSHOT)
endif
EMU_FLAGS = -s $(SEED) -b $(B) -e $(E) $(SNAPSHOT_OPTION) $(WAVEFORM)
emu: $(EMU)
ifeq ($(REMOTE),localhost)
@$(EMU) -i $(IMAGE) $(SEED) -b $(B) -e $(E) -v $(V)
@$(EMU) -i $(IMAGE) $(EMU_FLAGS)
else
ssh $(REMOTE) "cd $(REMOTE_PREFIX) && $(EMU) -i $(IMAGE) $(SEED) -b $(B) -e $(E) -v $(V)"
ssh -tt $(REMOTE) "cd $(REMOTE_PRJ_HOME) && export NOOP_HOME=$(REMOTE_PREFIX)/$(NOOP_HOME) && $(EMU) -i $(REMOTE_PREFIX)/$(IMAGE) $(EMU_FLAGS)"
endif
cache:
......
......@@ -53,3 +53,6 @@ libraryDependencies += "net.java.dev.jna" % "jna" % "4.0.0"
scalacOptions ++= scalacOptionsVersion(scalaVersion.value)
javacOptions ++= javacOptionsVersion(scalaVersion.value)
libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.2.1"
......@@ -53,6 +53,6 @@ trait HasMacroParadise extends ScalaModule {
object chiselModule extends CrossSbtModule with HasChisel3 with HasChiselTests with HasXsource211 with HasMacroParadise {
def zincWorker = CustomZincWorkerModule
def crossScalaVersion = "2.11.12"
def forkArgs = Seq("-Xmx3G")
def forkArgs = Seq("-Xmx10G")
}
......@@ -3,8 +3,9 @@ NANOS_HOME ?= $(AM_HOME)/../nanos-lite
SINGLETEST = ALL=min3
B ?= 0
E ?= -1
E ?= 0
V ?= ALL
#V ?= OFF
EMU_ARGS = B=$(B) E=$(E) V=$(V)
# ------------------------------------------------------------------
......@@ -19,39 +20,42 @@ cpu:
# ------------------------------------------------------------------
cputest:
$(MAKE) -C $(AM_HOME)/tests/cputest $(ARCH) run 2>&1 | tee > cpu.log
$(MAKE) -C $(AM_HOME)/tests/cputest $(ARCH) $(EMU_ARGS) run 2>&1 | tee > cpu.log
cat cpu.log | grep different
cat cpu.log | grep IPC
# bputest:
# $(MAKE) -C $(AM_HOME)/tests/bputest $(ARCH) run 2>&1 | tee > bpu.log
# cat bpu.log | grep different
bputest:
$(MAKE) -C $(AM_HOME)/tests/bputest $(ARCH) ALL=forcall2 run 2>&1 | tee > bpu.log
$(MAKE) -C $(AM_HOME)/tests/bputest $(ARCH) run 2 > bpu.log
cat bpu.log | grep Mbp
amtest:
$(MAKE) -C $(AM_HOME)/tests/cputest $(ARCH) $(SINGLETEST) run 2>&1 | tee > test.log
$(MAKE) -C $(AM_HOME)/tests/cputest $(ARCH) $(SINGLETEST) run 2 > test.log
cat test.log | grep different
cat test.log | grep ISU > isu.log
microbench:
$(MAKE) -C $(AM_HOME)/apps/microbench $(ARCH) mainargs=test run 2>&1 | tee > microbench.log
$(MAKE) -C $(AM_HOME)/apps/microbench $(ARCH) $(EMU_ARGS) mainargs=test run
#2 > microbench.log
cat microbench.log | grep IPC
microbench_train:
$(MAKE) -C $(AM_HOME)/apps/microbench $(ARCH) mainargs=train run 2>&1 | tee > microbench.log
$(MAKE) -C $(AM_HOME)/apps/microbench $(ARCH) $(EMU_ARGS) mainargs=train run 2 > microbench.log
cat microbench.log | grep IPC
coremark:
$(MAKE) -C $(AM_HOME)/apps/coremark $(ARCH) mainargs=test run 2>&1 | tee > coremark.log
$(MAKE) -C $(AM_HOME)/apps/coremark $(ARCH) $(EMU_ARGS) mainargs=test run
#2 > coremark.log
cat coremark.log | grep IPC
dhrystone:
$(MAKE) -C $(AM_HOME)/apps/dhrystone $(ARCH) mainargs=test run 2>&1 | tee > dhrystone.log
$(MAKE) -C $(AM_HOME)/apps/dhrystone $(ARCH) $(EMU_ARGS) mainargs=test run 2 > dhrystone.log
cat dhrystone.log | grep IPC
xj:
$(MAKE) -C $(NANOS_HOME) $(ARCH) run
$(MAKE) -C $(NANOS_HOME) $(ARCH) $(EMU_ARGS) run
xjnemu:
$(MAKE) -C $(NANOS_HOME) ARCH=riscv64-nemu run
......@@ -72,7 +76,7 @@ xv6-debug:
$(MAKE) -C $(XV6_HOME) noop 2>&1 | tee > xv6.log
linux:
$(MAKE) -C $(BBL_LINUX_HOME) noop
$(MAKE) -C $(BBL_LINUX_HOME) $(EMU_ARGS) noop
# ------------------------------------------------------------------
# get disassembled test src
# ------------------------------------------------------------------
......@@ -94,4 +98,11 @@ unit-test:
cd .. && mill chiselModule.test.testOnly -o -s $(SUITE) -P$(P)
unit-test-all:
cd .. && mill chiselModule.test.test -P$(P)
\ No newline at end of file
cd .. && mill chiselModule.test.test -P$(P)
# ------------------------------------------------------------------
# chore
# ------------------------------------------------------------------
clean:
$(MAKE) -C .. clean
import os
import argparse
def printMap(mp):
len_key = max(map(lambda s: len(s), mp.keys()))
len_value = max(map(lambda v: len(str(v)), mp.values()))
pattern = "{:<" +str(len_key) + "} {:<" +str(len_value)+ "} {:<7}%"
total = sum(mp.values())
for k,v in sorted(mp.items(), key=lambda x:x[1], reverse=True):
print(
pattern.format(k, v, round(v*100.0/total, 3))
)
def analyzeVerilog(filename):
mymap = {}
last = ""
with open(filename, "r") as f:
line = f.readline()
cnt = 0
while(line):
if "module " in line:
if last!="" :
mymap[last] = cnt
last = line[7:-2]
cnt = 1
else:
cnt = cnt + 1
line = f.readline()
mymap[last] = cnt
printMap(mymap)
logLevels = ['ALL', 'DEBUG', 'INFO', 'WARN', 'ERROR']
def listToStr(lst):
acc = ''
for l in lst:
acc += '|' + str(l) if acc else str(l)
return acc
def lineStrip(line):
return line.replace('\n', '')
def getNumLogLines(filename, modules, ll=logLevels):
cmd = "grep -E '\[({0}).*\]\[time=.*\] ({1}):' {2} | wc -l".format(
listToStr(ll),
listToStr(modules),
filename
)
res = os.popen(cmd)
return int(lineStrip(res.readline()), 10)
def analyzeLog(filename):
cmd = "grep -E '\[time=.*\]' {0} ".format(filename) + " | awk -F '(:)' {'print $1'} | awk {'print $NF'} | sort | uniq"
res = os.popen(cmd)
modules = list(map(lineStrip, res.readlines()))
mymap = {}
for m in modules:
mymap[m] = getNumLogLines(filename, [m])
printMap(mymap)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("-v", "--verilogFile", help="verilog file path", type=str)
parser.add_argument("-l", "--logFile", help="log file path", type=str)
args = parser.parse_args()
if args.verilogFile:
analyzeVerilog(args.verilogFile)
if args.logFile:
analyzeLog(args.logFile)
if not args.verilogFile and not args.logFile:
parser.print_help()
if __name__ == '__main__':
main()
/**************************************************************************************
* Copyright (c) 2020 Institute of Computing Technology, CAS
* Copyright (c) 2020 University of Chinese Academy of Sciences
*
* NutShell is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR
* FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
package bus.simplebus
import chisel3._
......@@ -11,7 +27,7 @@ class SimpleBusCrossbar1toN(addressSpace: List[(Long, Long)]) extends Module {
val out = Vec(addressSpace.length, new SimpleBusUC)
})
val s_idle :: s_resp :: Nil = Enum(2)
val s_idle :: s_resp :: s_error :: Nil = Enum(3)
val state = RegInit(s_idle)
// select the output channel according to the address
......@@ -22,8 +38,10 @@ class SimpleBusCrossbar1toN(addressSpace: List[(Long, Long)]) extends Module {
val outSel = io.out(outSelIdx)
val outSelIdxResp = RegEnable(outSelIdx, outSel.req.fire() && (state === s_idle))
val outSelResp = io.out(outSelIdxResp)
val reqInvalidAddr = io.in.req.valid && !outSelVec.asUInt.orR
assert(!io.in.req.valid || outSelVec.asUInt.orR, "address decode error, bad addr = 0x%x\n", addr)
when(!(!io.in.req.valid || outSelVec.asUInt.orR) || !(!(io.in.req.valid && outSelVec.asUInt.andR))){printf("[ERROR] bad addr %x, time %d\n", addr, GTimer())}
// assert(!io.in.req.valid || outSelVec.asUInt.orR, "address decode error, bad addr = 0x%x\n", addr)
assert(!(io.in.req.valid && outSelVec.asUInt.andR), "address decode error, bad addr = 0x%x\n", addr)
// bind out.req channel
......@@ -34,14 +52,19 @@ class SimpleBusCrossbar1toN(addressSpace: List[(Long, Long)]) extends Module {
}}
switch (state) {
is (s_idle) { when (outSel.req.fire()) { state := s_resp } }
is (s_idle) {
when (outSel.req.fire()) { state := s_resp }
when (reqInvalidAddr) { state := s_error }
}
is (s_resp) { when (outSelResp.resp.fire()) { state := s_idle } }
is (s_error) { when(io.in.resp.fire()){ state := s_idle } }
}
io.in.resp.valid := outSelResp.resp.fire()
io.in.resp.valid := outSelResp.resp.fire() || state === s_error
io.in.resp.bits <> outSelResp.resp.bits
// io.in.resp.bits.exc.get := state === s_error
outSelResp.resp.ready := io.in.resp.ready
io.in.req.ready := outSel.req.ready
io.in.req.ready := outSel.req.ready || reqInvalidAddr
Debug() {
when (state === s_idle && io.in.req.valid) {
......
......@@ -6,11 +6,9 @@ import chisel3._
import chisel3.util._
import xiangshan.XSModule
import xiangshan.utils.XSDebug
import bus.axi4.AXI4
import bus.axi4.AXI4Parameters
import utils.GTimer
import utils.MuxTLookup
import utils.{GTimer, MuxTLookup, XSDebug}
// It's a fake tilelink LLC
// It's only deals with AcquireBlock and ReleaseData from upper layer
......
......@@ -6,10 +6,8 @@ import chisel3._
import chisel3.util._
import xiangshan.XSModule
import xiangshan.utils.XSDebug
import bus.axi4.AXI4
import bus.axi4.AXI4Parameters
import utils.GTimer
import bus.axi4.{AXI4, AXI4Parameters}
import utils.{GTimer, XSDebug}
// a simpel TileLink to AXI4 converter
// only support TileLink put and get
......
......@@ -6,7 +6,7 @@ import chisel3._
import chisel3.util._
import xiangshan.HasXSParameter
import xiangshan.utils.XSDebug
import utils.XSDebug
case class TLParameters(
addressBits: Int = 64,
......
......@@ -3,7 +3,6 @@ package device
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import bus.axi4._
import utils._
......@@ -17,7 +16,7 @@ class AXI4Timer(sim: Boolean = false) extends AXI4SlaveModule(new AXI4Lite, new
val clk = (if (!sim) 40 /* 40MHz / 1000000 */ else 10000)
val freq = RegInit(clk.U(16.W))
val inc = RegInit(1.U(16.W))
val inc = RegInit(1000.U(16.W))
val cnt = RegInit(0.U(16.W))
val nextCnt = cnt + 1.U
......
......@@ -6,47 +6,30 @@ import chisel3.util._
import bus.axi4._
import utils._
class UARTGetc extends BlackBox with HasBlackBoxInline {
val io = IO(new Bundle {
val clk = Input(Clock())
val getc = Input(Bool())
class UARTIO extends Bundle {
val out = new Bundle {
val valid = Output(Bool())
val ch = Output(UInt(8.W))
})
setInline("UARTGetc.v",
s"""
|import "DPI-C" function void uart_getc(output byte ch);
|
|module UARTGetc (
| input clk,
| input getc,
| output reg [7:0] ch
|);
|
| always@(posedge clk) begin
| if (getc) uart_getc(ch);
| end
|
|endmodule
""".stripMargin)
}
val in = new Bundle {
val valid = Output(Bool())
val ch = Input(UInt(8.W))
}
}
class AXI4UART extends AXI4SlaveModule(new AXI4Lite) {
class AXI4UART extends AXI4SlaveModule(new AXI4Lite, new UARTIO) {
val rxfifo = RegInit(0.U(32.W))
val txfifo = Reg(UInt(32.W))
val stat = RegInit(1.U(32.W))
val ctrl = RegInit(0.U(32.W))
val getcHelper = Module(new UARTGetc)
getcHelper.io.clk := clock
getcHelper.io.getc := (raddr(3,0) === 0.U && ren)
def putc(c: UInt): UInt = { printf("%c", c(7,0)); c }
def getc = getcHelper.io.ch
io.extra.get.out.valid := (waddr(3,0) === 4.U && in.w.fire())
io.extra.get.out.ch := in.w.bits.data(7,0)
io.extra.get.in.valid := (raddr(3,0) === 0.U && ren)
val mapping = Map(
RegMap(0x0, getc, RegMap.Unwritable),
RegMap(0x4, txfifo, putc),
RegMap(0x0, io.extra.get.in.ch, RegMap.Unwritable),
RegMap(0x4, txfifo),
RegMap(0x8, stat),
RegMap(0xc, ctrl)
)
......
......@@ -181,7 +181,7 @@ sealed class CacheStage2(implicit val cacheConfig: CacheConfig) extends CacheMod
io.out.bits.hit := io.in.valid && hitVec.orR
io.out.bits.waymask := waymask
io.out.bits.datas := io.dataReadResp
io.out.bits.mmio := AddressSpace.isMMIO(req.addr)
io.out.bits.mmio := xiangshan.AddressSpace.isMMIO(req.addr)
val isForwardData = io.in.valid && (io.dataWriteBus.req match { case r =>
r.valid && r.bits.setIdx === getDataIdx(req.addr)
......@@ -542,6 +542,7 @@ object Cache {
empty := cache.io.empty
cache.io.out
} else {
assert(false, "XiangShan should not reach here!")
val addrspace = List(AddressSpace.dram) ++ AddressSpace.mmio
val xbar = Module(new SimpleBusCrossbar1toN(addrspace))
val busC = WireInit(0.U.asTypeOf(new SimpleBusC))
......
......@@ -135,20 +135,17 @@ class EXU(implicit val p: NOOPConfig) extends NOOPModule {
BoringUtils.addSource(csr.io.out.fire(), "perfCntCondMcsrInstr")
if (!p.FPGAPlatform) {
val mon = Module(new Monitor)
val nooptrap = io.in.bits.ctrl.isNoopTrap && io.in.valid
val cycleCnt = WireInit(0.U(XLEN.W))
val instrCnt = WireInit(0.U(XLEN.W))
val nooptrap = io.in.bits.ctrl.isNoopTrap && io.in.valid
mon.io.clk := clock
mon.io.reset := reset.asBool
mon.io.isNoopTrap := nooptrap
mon.io.trapCode := io.in.bits.data.src1
mon.io.trapPC := io.in.bits.cf.pc
mon.io.cycleCnt := cycleCnt
mon.io.instrCnt := instrCnt
BoringUtils.addSink(cycleCnt, "simCycleCnt")
BoringUtils.addSink(instrCnt, "simInstrCnt")
BoringUtils.addSource(nooptrap, "nooptrap")
BoringUtils.addSource(nooptrap, "trapValid")
BoringUtils.addSource(io.in.bits.data.src1, "trapCode")
BoringUtils.addSource(io.in.bits.cf.pc, "trapPC")
BoringUtils.addSource(cycleCnt, "trapCycleCnt")
BoringUtils.addSource(instrCnt, "trapInstrCnt")
}
}
......@@ -12,15 +12,3 @@ object NOOPTrap extends HasInstrType {
def TRAP = BitPat("b????????????_?????_000_?????_1101011")
val table = Array(TRAP -> List(InstrI, FuType.alu, ALUOpType.add))
}
class Monitor extends BlackBox {
val io = IO(new Bundle {
val clk = Input(Clock())
val reset = Input(Bool())
val isNoopTrap = Input(Bool())
val trapCode = Input(UInt(32.W))
val trapPC = Input(UInt(64.W))
val cycleCnt = Input(UInt(64.W))
val instrCnt = Input(UInt(64.W))
})
}
......@@ -241,7 +241,7 @@ class TLB(implicit val tlbConfig: TLBConfig) extends TlbModule{
val in = Flipped(new SimpleBusUC(userBits = userBits, addrBits = VAddrBits))
val out = new SimpleBusUC(userBits = userBits)
val mem = new SimpleBusUC()
val mem = new SimpleBusUC(userBits = userBits)
val flush = Input(Bool())
val csrMMU = new MMUIO
val cacheEmpty = Input(Bool())
......@@ -364,7 +364,7 @@ class TLBExec(implicit val tlbConfig: TLBConfig) extends TlbModule{
val mdWrite = new TLBMDWriteBundle(IndexBits = IndexBits, Ways = Ways, tlbLen = tlbLen)
val mdReady = Input(Bool())
val mem = new SimpleBusUC()
val mem = new SimpleBusUC(userBits = userBits)
val flush = Input(Bool())
val satp = Input(UInt(XLEN.W))
val pf = new MMUIO
......
package system
import noop.{Cache,CacheConfig}
import noop.{Cache, CacheConfig}
import bus.axi4.{AXI4, AXI4Lite}
import bus.simplebus._
import device.AXI4Timer
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import xiangshan.{XSConfig, XSCore}
import top.Parameters
import xiangshan.XSCore
case class SoCParameters
(
EnableILA: Boolean = false,
HasL2Cache: Boolean = false,
HasPrefetch: Boolean = false
)
trait HasSoCParameter {
val EnableILA = true
val HasL2cache = true
val HasPrefetch = true
val soc = Parameters.get.socParameters
val env = Parameters.get.envParameters
val EnableILA = soc.EnableILA
val HasL2cache = soc.HasL2Cache
val HasPrefetch = soc.HasPrefetch
}
class ILABundle extends Bundle {}
class XSSoc(implicit val p: XSConfig) extends Module with HasSoCParameter {
class XSSoc extends Module with HasSoCParameter {
val io = IO(new Bundle{
val mem = new AXI4
val mmio = if (p.FPGAPlatform) { new AXI4Lite } else { new SimpleBusUC }
val mmio = if (env.FPGAPlatform) { new AXI4Lite } else { new SimpleBusUC }
val frontend = Flipped(new AXI4)
val meip = Input(Bool())
val ila = if (p.FPGAPlatform && EnableILA) Some(Output(new ILABundle)) else None
val ila = if (env.FPGAPlatform && EnableILA) Some(Output(new ILABundle)) else None
})
val xsCore = Module(new XSCore)
......@@ -63,20 +74,20 @@ class XSSoc(implicit val p: XSConfig) extends Module with HasSoCParameter {
xsCore.io.imem.coh.req.bits := DontCare
val addrSpace = List(
(0x40000000L, 0x08000000L), // external devices
(0x40000000L, 0x40000000L), // external devices
(0x38000000L, 0x00010000L) // CLINT
)
val mmioXbar = Module(new SimpleBusCrossbar1toN(addrSpace))
mmioXbar.io.in <> xsCore.io.mmio
val extDev = mmioXbar.io.out(0)
val clint = Module(new AXI4Timer(sim = !p.FPGAPlatform))
val clint = Module(new AXI4Timer(sim = !env.FPGAPlatform))
clint.io.in <> mmioXbar.io.out(1).toAXI4Lite()
if (p.FPGAPlatform) io.mmio <> extDev.toAXI4Lite()
if (env.FPGAPlatform) io.mmio <> extDev.toAXI4Lite()
else io.mmio <> extDev
val mtipSync = clint.io.extra.get.mtip
val meipSync = RegNext(RegNext(io.meip))
BoringUtils.addSource(mtipSync, "mtip")
BoringUtils.addSource(meipSync, "meip")
}
\ No newline at end of file
}
package top
import system.SoCParameters
import xiangshan.{EnviromentParameters, XSCoreParameters}
case class Parameters
(
coreParameters: XSCoreParameters = XSCoreParameters(),
socParameters: SoCParameters = SoCParameters(),
envParameters: EnviromentParameters = EnviromentParameters()
){
require(
!(envParameters.FPGAPlatform && envParameters.EnableDebug),
"Enable debug(display log) is only supported in simulation enviroment!"
)
require(
!(socParameters.EnableILA && !envParameters.FPGAPlatform),
"ILA is only supported in FPGA platform!"
)
}
object Parameters {
val defaultParameters = Parameters()
val simParameters = Parameters(envParameters = EnviromentParameters(FPGAPlatform = false)) // sim only, disable log
val debugParameters = Parameters(envParameters = simParameters.envParameters.copy(EnableDebug = true)) // open log
private var parameters = Parameters() // a default parameter, can be updated before use
def get: Parameters = parameters
def set(p: Parameters): Unit = {
parameters = p
}
}
......@@ -5,11 +5,10 @@ import device.{AXI4Flash, AXI4Timer, AXI4VGA}
import gpu._
import chisel3._
import chisel3.stage.ChiselGeneratorAnnotation
import xiangshan.XSConfig
class Top extends Module {
val io = IO(new Bundle{})
val xsSoc = Module(new XSSoc()(XSConfig()))
val xsSoc = Module(new XSSoc())
val timer = Module(new AXI4Timer)
val vga = Module(new AXI4VGA)
val flash = Module(new AXI4Flash)
......
......@@ -59,3 +59,21 @@ object OneHot {
def UIntToOH1(x: UInt, width: Int): UInt = ~((-1).S(width.W).asUInt << x)(width-1, 0)
def UIntToOH1(x: UInt): UInt = UIntToOH1(x, (1 << x.getWidth) - 1)
}
object LowerMask {
def apply(a: UInt, len: Int) = {
(0 until len).map(i => a >> i.U).reduce(_|_)
}
}
object LowestBit {
def apply(a: UInt, len: Int) = {
Mux(a(0), 1.U(len.W), Reverse(((0 until len).map(i => Reverse(a(len - 1, 0)) >> i.U).reduce(_|_) + 1.U) >> 1.U))
}
}
object HighestBit {
def apply(a: UInt, len: Int) = {
Reverse(LowestBit(Reverse(a), len))
}
}
package chisel3
import chisel3.internal.NamedComponent
import chisel3.util.experimental.BoringUtils
import scala.collection.mutable
object ExcitingUtils {
object ConnectionType extends Enumeration {
val Perf = Value("perf")
val Func = Value("func")
val Debug = Value("debug")
}
type ConnectionType = ConnectionType.Value
val Perf = ConnectionType.Perf
val Func = ConnectionType.Func
val Debug = ConnectionType.Debug
private def strToErrorMsg(str: String) = "\u001b[1m\u001b[;31m"+ str +"\u001b[0m"
private class Connection
(
var connType: ConnectionType,
var sourceModule: Option[String] = None,
var sinkModule: Option[String] = None
){
override def toString: String =
s"type:[$connType] source location:[${sourceModule.getOrElse(strToErrorMsg("Not Found"))}]" +
s" sink location:[${sinkModule.getOrElse(strToErrorMsg("Not Found"))}]"
def isLeagleConnection: Boolean = sourceModule.nonEmpty && sinkModule.nonEmpty
}
private val map = mutable.LinkedHashMap[String, Connection]()
def addSource
(
component: NamedComponent,
name: String,
connType: ConnectionType = Func,
disableDedup: Boolean = false,
uniqueName: Boolean = false
): String = {
val conn = map.getOrElseUpdate(name, new Connection(connType))
require(conn.connType == connType)
conn.sourceModule = Some(component.parentModName)
BoringUtils.addSource(component, name, disableDedup, uniqueName)
}
def addSink
(
component: InstanceId,
name: String,
connType: ConnectionType = Func,
disableDedup: Boolean = false,
forceExists: Boolean = false
): Unit = {
val conn = map.getOrElseUpdate(name, new Connection(connType))
require(conn.connType == connType)
conn.sinkModule = Some(component.parentModName)
BoringUtils.addSink(component, name, disableDedup, forceExists)
}
def checkAndDisplay(): Unit = {
var leagle = true
val buf = new mutable.StringBuilder()
for((id, conn) <- map){
buf ++= s"Connection:[$id] $conn\n"
if(!conn.isLeagleConnection) leagle = false
}
print(buf)
require(leagle, strToErrorMsg("Error: Illeagle connection found!"))
}
}
package utils
import chisel3._
import chisel3.util._
object GTimer {
def apply() = {
......
package xiangshan.utils
package utils
import chisel3._
import chisel3.util.experimental.BoringUtils
import top.Parameters
import xiangshan.HasXSParameter
import xiangshan.utils.XSLogLevel.XSLogLevel
import utils.XSLogLevel.XSLogLevel
object XSLogLevel extends Enumeration {
type XSLogLevel = Value
......@@ -17,29 +18,33 @@ object XSLogLevel extends Enumeration {
}
object XSLog {
def displayLog: Bool = {
val disp_begin, disp_end = WireInit(0.U(64.W))
BoringUtils.addSink(disp_begin, "DISPLAY_LOG_START")
BoringUtils.addSink(disp_end, "DISPLAY_LOG_END")
assert(disp_begin <= disp_end)
(GTimer() >= disp_begin) && (GTimer() <= disp_end)
}
def xsLogLevel: UInt = {
val log_level = WireInit(0.U(64.W))
BoringUtils.addSink(log_level, "DISPLAY_LOG_LEVEL")
assert(log_level < XSLogLevel.maxId.U)
log_level
}
def apply(debugLevel: XSLogLevel)
(prefix: Boolean, cond: Bool, pable: Printable)
(implicit name: String): Any = {
val commonInfo = p"[$debugLevel][time=${GTimer()}] $name: "
when (debugLevel.id.U >= xsLogLevel && cond && displayLog) {
printf((if (prefix) commonInfo else p"") + pable)
(implicit name: String): Any =
{
val logEnable = WireInit(false.B)
val logTimestamp = WireInit(0.U(64.W))
ExcitingUtils.addSink(logEnable, "DISPLAY_LOG_ENABLE")
ExcitingUtils.addSink(logTimestamp, "logTimestamp")
if(Parameters.get.envParameters.EnableDebug){
when (cond && logEnable) {
val commonInfo = p"[$debugLevel][time=$logTimestamp] $name: "
printf((if (prefix) commonInfo else p"") + pable)
if (debugLevel >= XSLogLevel.ERROR) {
assert(false.B)
}
}
}
}
def displayLog: Bool = {
val logEnable = WireInit(false.B)
ExcitingUtils.addSink(logEnable, "DISPLAY_LOG_ENABLE")
val ret = WireInit(false.B)
if(Parameters.get.envParameters.EnableDebug) {
ret := logEnable
}
ret
}
}
......@@ -59,7 +64,7 @@ sealed abstract class LogHelper(val logLevel: XSLogLevel) extends HasXSParameter
// trigger log or not
// used when user what to fine-control their printf output
def trigger: Bool = {
logLevel.id.U >= XSLog.xsLogLevel && XSLog.displayLog
XSLog.displayLog
}
def printPrefix()(implicit name: String): Unit = {
......
package xiangshan.utils
package utils
import chisel3._
import chisel3.experimental.{DataMirror, requireIsChiselType}
......
package xiangshan.utils
package utils
import chisel3._
import chisel3.util._
object ParallelOperation {
def apply(xs: Seq[UInt], func: (UInt, UInt) => UInt): UInt = {
def apply[T <: Data](xs: Seq[T], func: (T, T) => T): T = {
xs match {
case Seq(a) => a
case Seq(a, b) => func(a, b)
......@@ -15,21 +15,21 @@ object ParallelOperation {
}
object ParallelOR {
def apply(xs: Seq[UInt]): UInt = {
ParallelOperation(xs, (a, b) => a | b)
def apply[T <: Data](xs: Seq[T]): T = {
ParallelOperation(xs, (a: T, b: T) => (a.asUInt() | b.asUInt()).asTypeOf(xs.head))
}
}
object ParallelAND {
def apply(xs: Seq[UInt]): UInt = {
ParallelOperation(xs, (a, b) => a & b)
def apply[T <: Data](xs: Seq[T]): T = {
ParallelOperation(xs, (a: T, b:T) => (a.asUInt() & b.asUInt()).asTypeOf(xs.head))
}
}
object ParallelMux {
def apply[T<:Data](in: Seq[(Bool, T)]): T = {
val xs = in map { case (cond, x) => Fill(x.getWidth, cond) & x.asUInt() }
ParallelOR(xs).asInstanceOf[T]
val xs = in map { case (cond, x) => (Fill(x.getWidth, cond) & x.asUInt()).asTypeOf(in.head._2) }
ParallelOR(xs)
}
}
......
......@@ -11,7 +11,7 @@ object PipelineConnect {
when (isFlush) { valid := false.B }
left.ready := right.ready
right.bits <> RegEnable(left.bits, left.valid && right.ready)
right.bits := RegEnable(left.bits, left.valid && right.ready)
right.valid := valid //&& !isFlush
}
}
package xiangshan.utils
package utils
import chisel3._
......@@ -17,4 +17,27 @@ object PriorityEncoderDefault {
def apply(in: Seq[Bool], default: UInt): UInt = {
PriorityMuxDefault(in.zipWithIndex.map(x => x._1 -> x._2.U), default)
}
}
object PriorityMuxWithFlag {
def apply[T <: Data](in: Seq[(Bool, T)]): (T, Bool) = {
in.size match {
case 1 =>
(in.head._2, in.head._1)
case _ =>
val (d_tail, f_tail) = PriorityMuxWithFlag(in.tail)
val d_head = in.head._2
val f_head = in.head._1
(Mux(f_head, d_head, d_tail), f_head || f_tail)
}
}
}
object PriorityEncoderWithFlag {
def apply(in: Seq[Bool]): (UInt, Bool) = {
PriorityMuxWithFlag(in.zipWithIndex.map(x => x._1 -> x._2.U))
}
def apply(in: Bits): (UInt, Bool) = {
PriorityEncoderWithFlag(in.asBools())
}
}
\ No newline at end of file
package utils
import chisel3._
import chisel3.util._
object BoolStopWatch {
def apply(start: Bool, stop: Bool, startHighPriority: Boolean = false) = {
......
......@@ -5,12 +5,88 @@ import chisel3.util._
import bus.simplebus._
import xiangshan.backend.brq.BrqPtr
import xiangshan.backend.rename.FreeListPtr
import xiangshan.frontend.PreDecodeInfo
// Fetch FetchWidth x 32-bit insts from Icache
class FetchPacket extends XSBundle {
val instrs = Vec(FetchWidth, UInt(32.W))
val instrs = Vec(PredictWidth, UInt(32.W))
val mask = UInt(PredictWidth.W)
// val pc = UInt(VAddrBits.W)
val pc = Vec(PredictWidth, UInt(VAddrBits.W))
val pnpc = Vec(PredictWidth, UInt(VAddrBits.W))
val brInfo = Vec(PredictWidth, new BranchInfo)
val pd = Vec(PredictWidth, new PreDecodeInfo)
}
class ValidUndirectioned[T <: Data](gen: T) extends Bundle {
val valid = Bool()
val bits = gen.cloneType.asInstanceOf[T]
override def cloneType = new ValidUndirectioned(gen).asInstanceOf[this.type]
}
object ValidUndirectioned {
def apply[T <: Data](gen: T) = {
new ValidUndirectioned[T](gen)
}
}
class TageMeta extends XSBundle {
def TageNTables = 6
val provider = ValidUndirectioned(UInt(log2Ceil(TageNTables).W))
val altDiffers = Bool()
val providerU = UInt(2.W)
val providerCtr = UInt(3.W)
val allocate = ValidUndirectioned(UInt(log2Ceil(TageNTables).W))
}
class BranchPrediction extends XSBundle {
val redirect = Bool()
val taken = Bool()
val jmpIdx = UInt(log2Up(PredictWidth).W)
val hasNotTakenBrs = Bool()
val target = UInt(VAddrBits.W)
val saveHalfRVI = Bool()
}
class BranchInfo extends XSBundle {
val ubtbWriteWay = UInt(log2Up(UBtbWays).W)
val ubtbHits = Bool()
val btbWriteWay = UInt(log2Up(BtbWays).W)
val bimCtr = UInt(2.W)
val histPtr = UInt(log2Up(ExtHistoryLength).W)
val tageMeta = new TageMeta
val rasSp = UInt(log2Up(RasSize).W)
val rasTopCtr = UInt(8.W)
def apply(histPtr: UInt, tageMeta: TageMeta, rasSp: UInt, rasTopCtr: UInt) = {
this.histPtr := histPtr
this.tageMeta := tageMeta
this.rasSp := rasSp
this.rasTopCtr := rasTopCtr
this.asUInt
}
def size = 0.U.asTypeOf(this).getWidth
def fromUInt(x: UInt) = x.asTypeOf(this)
}
class Predecode extends XSBundle {
val mask = UInt((FetchWidth*2).W)
val pc = UInt(VAddrBits.W) // the pc of first inst in the fetch group
val pd = Vec(FetchWidth*2, (new PreDecodeInfo))
}
class BranchUpdateInfo extends XSBundle {
// from backend
val pc = UInt(VAddrBits.W)
val pnpc = UInt(VAddrBits.W)
val target = UInt(VAddrBits.W)
val brTarget = UInt(VAddrBits.W)
val taken = Bool()
val fetchIdx = UInt(log2Up(FetchWidth*2).W)
val isMisPred = Bool()
// frontend -> backend -> frontend
val pd = new PreDecodeInfo
val brInfo = new BranchInfo
}
// Dequeue DecodeWidth insts from Ibuffer
......@@ -19,8 +95,8 @@ class CtrlFlow extends XSBundle {
val pc = UInt(VAddrBits.W)
val exceptionVec = Vec(16, Bool())
val intrVec = Vec(12, Bool())
val isRVC = Bool()
val isBr = Bool()
val brUpdate = new BranchUpdateInfo
val crossPageIPFFix = Bool()
}
// Decode DecodeWidth insts at Decode Stage
......@@ -37,6 +113,7 @@ class CtrlSignals extends XSBundle {
val isBlocked = Bool() // This inst requires pipeline to be blocked
val isRVF = Bool()
val imm = UInt(XLEN.W)
val dpqType = DPQType()
}
class CfCtrl extends XSBundle {
......@@ -45,36 +122,46 @@ class CfCtrl extends XSBundle {
val brTag = new BrqPtr
}
// CfCtrl -> MicroOp at Rename Stage
class MicroOp extends CfCtrl {
trait HasRoqIdx { this: HasXSParameter =>
val roqIdx = UInt(RoqIdxWidth.W)
def isAfter(thatIdx: UInt): Bool = {
Mux(
this.roqIdx.head(1) === thatIdx.head(1),
this.roqIdx.tail(1) > thatIdx.tail(1),
this.roqIdx.tail(1) < thatIdx.tail(1)
)
}
def isAfter[ T<: HasRoqIdx ](that: T): Bool = {
isAfter(that.roqIdx)
}
def needFlush(redirect: Valid[Redirect]): Bool = {
redirect.valid && this.isAfter(redirect.bits.roqIdx)
}
}
// CfCtrl -> MicroOp at Rename Stage
class MicroOp extends CfCtrl with HasRoqIdx {
val psrc1, psrc2, psrc3, pdest, old_pdest = UInt(PhyRegIdxWidth.W)
val src1State, src2State, src3State = SrcState()
val freelistAllocPtr = new FreeListPtr
val roqIdx = UInt(RoqIdxWidth.W)
val moqIdx = UInt(MoqIdxWidth.W)
}
class Redirect extends XSBundle {
class Redirect extends XSBundle with HasRoqIdx {
val isException = Bool()
val isMisPred = Bool()
val isReplay = Bool()
val pc = UInt(VAddrBits.W)
val target = UInt(VAddrBits.W)
val brTag = new BrqPtr
val isException = Bool()
val roqIdx = UInt(RoqIdxWidth.W)
val freelistAllocPtr = new FreeListPtr
}
class RedirectInfo extends XSBundle {
val valid = Bool() // a valid commit form brq/roq
val misPred = Bool() // a branch miss prediction ?
val redirect = new Redirect
def flush():Bool = valid && (redirect.isException || misPred)
}
class Dp1ToDp2IO extends XSBundle {
val intDqToDp2 = Vec(IntDqDeqWidth, DecoupledIO(new MicroOp))
val fpDqToDp2 = Vec(FpDqDeqWidth, DecoupledIO(new MicroOp))
val lsDqToDp2 = Vec(LsDqDeqWidth, DecoupledIO(new MicroOp))
val intDqToDp2 = Vec(dpParams.IntDqDeqWidth, DecoupledIO(new MicroOp))
val fpDqToDp2 = Vec(dpParams.FpDqDeqWidth, DecoupledIO(new MicroOp))
val lsDqToDp2 = Vec(dpParams.LsDqDeqWidth, DecoupledIO(new MicroOp))
}
class DebugBundle extends XSBundle{
......@@ -91,6 +178,7 @@ class ExuOutput extends XSBundle {
val data = UInt(XLEN.W)
val redirectValid = Bool()
val redirect = new Redirect
val brUpdate = new BranchUpdateInfo
val debug = new DebugBundle
}
......@@ -98,10 +186,11 @@ class ExuIO extends XSBundle {
val in = Flipped(DecoupledIO(new ExuInput))
val redirect = Flipped(ValidIO(new Redirect))
val out = DecoupledIO(new ExuOutput)
// for csr
val exception = Flipped(ValidIO(new MicroOp))
// for Lsu
val dmem = new SimpleBusUC
val scommit = Input(UInt(3.W))
val mcommit = Input(UInt(3.W))
}
class RoqCommit extends XSBundle {
......@@ -109,10 +198,15 @@ class RoqCommit extends XSBundle {
val isWalk = Bool()
}
class TlbFeedback extends XSBundle with HasRoqIdx{
val hit = Bool()
}
class FrontendToBackendIO extends XSBundle {
// to backend end
val cfVec = Vec(DecodeWidth, DecoupledIO(new CtrlFlow))
// from backend
val redirectInfo = Input(new RedirectInfo)
val commits = Vec(CommitWidth, Flipped(ValidIO(new RoqCommit))) // update branch pred
val redirect = Flipped(ValidIO(new Redirect))
val outOfOrderBrInfo = Flipped(ValidIO(new BranchUpdateInfo))
val inOrderBrInfo = Flipped(ValidIO(new BranchUpdateInfo))
}
......@@ -4,65 +4,152 @@ import chisel3._
import chisel3.util._
import bus.simplebus._
import noop.{Cache, CacheConfig, HasExceptionNO, TLB, TLBConfig}
import top.Parameters
import xiangshan.backend._
import xiangshan.backend.dispatch.DP1Parameters
import xiangshan.backend.dispatch.DispatchParameters
import xiangshan.backend.exu.ExuParameters
import xiangshan.frontend.Frontend
import xiangshan.frontend._
import xiangshan.mem._
import xiangshan.mem.cache.ICacheParameters
import xiangshan.mem.cache.DCacheParameters
import xiangshan.utils._
import xiangshan.mem.cache.{ICacheParameters, DCacheParameters}
import bus.tilelink.TLParameters
import utils._
case class XSCoreParameters
(
XLEN: Int = 64,
HasMExtension: Boolean = true,
HasCExtension: Boolean = true,
HasDiv: Boolean = true,
HasICache: Boolean = true,
HasDCache: Boolean = true,
EnableStoreQueue: Boolean = true,
AddrBits: Int = 64,
VAddrBits: Int = 39,
PAddrBits: Int = 32,
HasFPU: Boolean = true,
FectchWidth: Int = 8,
EnableBPU: Boolean = true,
EnableBPD: Boolean = false,
EnableRAS: Boolean = false,
EnableLB: Boolean = false,
HistoryLength: Int = 64,
BtbSize: Int = 256,
JbtacSize: Int = 1024,
JbtacBanks: Int = 8,
RasSize: Int = 16,
CacheLineSize: Int = 512,
UBtbWays: Int = 16,
BtbWays: Int = 2,
IBufSize: Int = 64,
DecodeWidth: Int = 6,
RenameWidth: Int = 6,
CommitWidth: Int = 6,
BrqSize: Int = 16,
IssQueSize: Int = 8,
NRPhyRegs: Int = 128,
NRIntReadPorts: Int = 8,
NRIntWritePorts: Int = 8,
NRFpReadPorts: Int = 14,
NRFpWritePorts: Int = 8,
MoqSize: Int = 16,
RoqSize: Int = 32,
IntDqDeqWidth: Int = 4,
FpDqDeqWidth: Int = 4,
LsDqDeqWidth: Int = 4,
dpParams: DispatchParameters = DispatchParameters(
DqEnqWidth = 4,
IntDqSize = 64,
FpDqSize = 64,
LsDqSize = 64,
IntDqDeqWidth = 4,
FpDqDeqWidth = 4,
LsDqDeqWidth = 4
),
exuParameters: ExuParameters = ExuParameters(
JmpCnt = 1,
AluCnt = 4,
MulCnt = 0,
MduCnt = 2,
FmacCnt = 0,
FmiscCnt = 0,
FmiscDivSqrtCnt = 0,
LduCnt = 2,
StuCnt = 2
),
LoadPipelineWidth: Int = 2,
StorePipelineWidth: Int = 2,
StoreBufferSize: Int = 16,
RefillSize: Int = 512
)
trait HasXSParameter {
val XLEN = 64
val HasMExtension = true
val HasCExtension = true
val HasDiv = true
val HasIcache = true
val HasDcache = true
val EnableStoreQueue = false
val AddrBits = 64 // AddrBits is used in some cases
val VAddrBits = 39 // VAddrBits is Virtual Memory addr bits
val PAddrBits = 32 // PAddrBits is Phyical Memory addr bits
val core = Parameters.get.coreParameters
val env = Parameters.get.envParameters
val XLEN = core.XLEN
val HasMExtension = core.HasMExtension
val HasCExtension = core.HasCExtension
val HasDiv = core.HasDiv
val HasIcache = core.HasICache
val HasDcache = core.HasDCache
val EnableStoreQueue = core.EnableStoreQueue
val AddrBits = core.AddrBits // AddrBits is used in some cases
val VAddrBits = core.VAddrBits // VAddrBits is Virtual Memory addr bits
val PAddrBits = core.PAddrBits // PAddrBits is Phyical Memory addr bits
val AddrBytes = AddrBits / 8 // unused
val DataBits = XLEN
val DataBytes = DataBits / 8
val HasFPU = true
val FetchWidth = 8
val IBufSize = 64
val DecodeWidth = 6
val RenameWidth = 6
val CommitWidth = 6
val BrqSize = 16
val IssQueSize = 8
val HasFPU = core.HasFPU
val FetchWidth = core.FectchWidth
val PredictWidth = FetchWidth * 2
val EnableBPU = core.EnableBPU
val EnableBPD = core.EnableBPD // enable backing predictor(like Tage) in BPUStage3
val EnableRAS = core.EnableRAS
val EnableLB = core.EnableLB
val HistoryLength = core.HistoryLength
val BtbSize = core.BtbSize
// val BtbWays = 4
val BtbBanks = PredictWidth
// val BtbSets = BtbSize / BtbWays
val JbtacSize = core.JbtacSize
val JbtacBanks = core.JbtacBanks
val RasSize = core.RasSize
val CacheLineSize = core.CacheLineSize
val CacheLineHalfWord = CacheLineSize / 16
val ExtHistoryLength = HistoryLength * 2
val UBtbWays = core.UBtbWays
val BtbWays = core.BtbWays
val IBufSize = core.IBufSize
val DecodeWidth = core.DecodeWidth
val RenameWidth = core.RenameWidth
val CommitWidth = core.CommitWidth
val BrqSize = core.BrqSize
val IssQueSize = core.IssQueSize
val BrTagWidth = log2Up(BrqSize)
val NRPhyRegs = 128
val NRPhyRegs = core.NRPhyRegs
val PhyRegIdxWidth = log2Up(NRPhyRegs)
val NRReadPorts = 14
val NRWritePorts = 8
val RoqSize = 32
val MoqSize = core.MoqSize // 64
val RoqSize = core.RoqSize
val InnerRoqIdxWidth = log2Up(RoqSize)
val RoqIdxWidth = InnerRoqIdxWidth + 1
val IntDqDeqWidth = 4
val FpDqDeqWidth = 4
val LsDqDeqWidth = 4
val dp1Paremeters = DP1Parameters(
IntDqSize = 16,
FpDqSize = 16,
LsDqSize = 16
)
val exuParameters = ExuParameters(
JmpCnt = 1,
AluCnt = 4,
MulCnt = 1,
MduCnt = 1,
FmacCnt = 0,
FmiscCnt = 0,
FmiscDivSqrtCnt = 0,
LduCnt = 0,
StuCnt = 1
)
val InnerMoqIdxWidth = log2Up(MoqSize)
val MoqIdxWidth = InnerMoqIdxWidth + 1
val IntDqDeqWidth = core.IntDqDeqWidth
val FpDqDeqWidth = core.FpDqDeqWidth
val LsDqDeqWidth = core.LsDqDeqWidth
val dpParams = core.dpParams
val exuParameters = core.exuParameters
val NRIntReadPorts = core.NRIntReadPorts
val NRIntWritePorts = core.NRIntWritePorts
val NRMemReadPorts = exuParameters.LduCnt + 2*exuParameters.StuCnt
val NRFpReadPorts = core.NRFpReadPorts
val NRFpWritePorts = core.NRFpWritePorts
val LoadPipelineWidth = core.LoadPipelineWidth
val StorePipelineWidth = core.StorePipelineWidth
val StoreBufferSize = core.StoreBufferSize
val RefillSize = core.RefillSize
val l1BusDataWidth = 64
val l1BusParams = TLParameters(
......@@ -75,8 +162,6 @@ trait HasXSParameter {
val icacheParameters = ICacheParameters(
)
// the width of LSU to DCache IO
val memWidth = 2
val LRSCCycles = 16
val dcacheParameters = DCacheParameters(
busParams = l1BusParams
......@@ -104,10 +189,10 @@ trait NeedImpl { this: Module =>
abstract class XSBundle extends Bundle
with HasXSParameter
case class XSConfig
case class EnviromentParameters
(
FPGAPlatform: Boolean = true,
EnableDebug: Boolean = true
EnableDebug: Boolean = false
)
object AddressSpace extends HasXSParameter {
......@@ -126,7 +211,7 @@ object AddressSpace extends HasXSParameter {
}
class XSCore(implicit val p: XSConfig) extends XSModule {
class XSCore extends XSModule {
val io = IO(new Bundle {
val imem = new SimpleBusC
val dmem = new SimpleBusC
......@@ -134,28 +219,35 @@ class XSCore(implicit val p: XSConfig) extends XSModule {
val frontend = Flipped(new SimpleBusUC())
})
io.imem <> DontCare
io.imem <> DontCare
io.dmem <> DontCare
io.mmio <> DontCare
io.frontend <> DontCare
val dmemXbar = Module(new SimpleBusCrossbarNto1(3))
/*
val DcacheUserBundleWidth = (new DcacheUserBundle).getWidth
val dmemXbar = Module(new SimpleBusCrossbarNto1(n = 2, userBits = DcacheUserBundleWidth))
val front = Module(new Frontend)
val backend = Module(new Backend)
val mem = Module(new MemPipeline)
mem.io := DontCare // FIXME
val mem = Module(new Memend)
front.io.backend <> backend.io.frontend
mem.io.backend <> backend.io.mem
backend.io.memMMU.imem <> DontCare
val dtlb = TLB(
in = backend.io.dmem,
in = mem.io.dmem,
mem = dmemXbar.io.in(1),
flush = false.B,
csrMMU = backend.io.memMMU.dmem
)(TLBConfig(name = "dtlb", totalEntry = 64))
)(TLBConfig(name = "dtlb", totalEntry = 64, userBits = DcacheUserBundleWidth))
dmemXbar.io.in(0) <> dtlb.io.out
dmemXbar.io.in(2) <> io.frontend
// dmemXbar.io.in(1) <> io.frontend
io.frontend <> DontCare
io.dmem <> Cache(
in = dmemXbar.io.out,
......@@ -163,29 +255,7 @@ class XSCore(implicit val p: XSConfig) extends XSModule {
flush = "b00".U,
empty = dtlb.io.cacheEmpty,
enable = HasDcache
)(CacheConfig(name = "dcache"))
XSDebug("(req valid, ready | resp valid, ready) \n")
XSDebug("c-mem(%x %x %x| %x %x) c-coh(%x %x %x| %x %x) cache (%x %x %x| %x %x) tlb (%x %x %x| %x %x)\n",
io.dmem.mem.req.valid,
io.dmem.mem.req.ready,
io.dmem.mem.req.bits.addr,
io.dmem.mem.resp.valid,
io.dmem.mem.resp.ready,
io.dmem.coh.req.valid,
io.dmem.coh.req.ready,
io.dmem.coh.req.bits.addr,
io.dmem.coh.resp.valid,
io.dmem.coh.resp.ready,
dmemXbar.io.out.req.valid,
dmemXbar.io.out.req.ready,
dmemXbar.io.out.req.bits.addr,
dmemXbar.io.out.resp.valid,
dmemXbar.io.out.resp.ready,
backend.io.dmem.req.valid,
backend.io.dmem.req.ready,
backend.io.dmem.req.bits.addr,
backend.io.dmem.resp.valid,
backend.io.dmem.resp.ready
)
)(CacheConfig(name = "dcache", userBits = DcacheUserBundleWidth))
*/
}
......@@ -12,140 +12,214 @@ import xiangshan.backend.brq.Brq
import xiangshan.backend.dispatch.Dispatch
import xiangshan.backend.exu._
import xiangshan.backend.fu.FunctionUnit
import xiangshan.backend.issue.IssueQueue
import xiangshan.backend.issue.{IssueQueue, ReservationStation}
import xiangshan.backend.regfile.{Regfile, RfWritePort}
import xiangshan.backend.roq.Roq
import xiangshan.mem._
import utils.ParallelOR
/** Backend Pipeline:
* Decode -> Rename -> Dispatch-1 -> Dispatch-2 -> Issue -> Exe
*/
class Backend(implicit val p: XSConfig) extends XSModule
with HasExeUnits
class Backend extends XSModule
with NeedImpl {
val io = IO(new Bundle {
val dmem = new SimpleBusUC(addrBits = VAddrBits)
// val dmem = new SimpleBusUC(addrBits = VAddrBits)
val memMMU = Flipped(new MemMMUIO)
val frontend = Flipped(new FrontendToBackendIO)
val mem = Flipped(new MemToBackendIO)
})
val aluExeUnits = Array.tabulate(exuParameters.AluCnt)(_ => Module(new AluExeUnit))
val jmpExeUnit = Module(new JmpExeUnit)
val mulExeUnits = Array.tabulate(exuParameters.MulCnt)(_ => Module(new MulExeUnit))
val mduExeUnits = Array.tabulate(exuParameters.MduCnt)(_ => Module(new MulDivExeUnit))
// val fmacExeUnits = Array.tabulate(exuParameters.FmacCnt)(_ => Module(new Fmac))
// val fmiscExeUnits = Array.tabulate(exuParameters.FmiscCnt)(_ => Module(new Fmisc))
// val fmiscDivSqrtExeUnits = Array.tabulate(exuParameters.FmiscDivSqrtCnt)(_ => Module(new FmiscDivSqrt))
val exeUnits = jmpExeUnit +: (aluExeUnits ++ mulExeUnits ++ mduExeUnits)
exeUnits.foreach(_.io.exception := DontCare)
exeUnits.foreach(_.io.dmem := DontCare)
exeUnits.foreach(_.io.mcommit := DontCare)
val decode = Module(new DecodeStage)
val brq = Module(new Brq)
val decBuf = Module(new DecodeBuffer)
val rename = Module(new Rename)
val dispatch = Module(new Dispatch(exeUnits.map(_.config)))
val dispatch = Module(new Dispatch())
val roq = Module(new Roq)
val intRf = Module(new Regfile(
numReadPorts = NRReadPorts,
numWirtePorts = NRWritePorts,
numReadPorts = NRIntReadPorts,
numWirtePorts = NRIntWritePorts,
hasZero = true
))
val fpRf = Module(new Regfile(
numReadPorts = NRReadPorts,
numWirtePorts = NRWritePorts,
numReadPorts = NRFpReadPorts,
numWirtePorts = NRFpWritePorts,
hasZero = false
))
val memRf = Module(new Regfile(
numReadPorts = 2*exuParameters.StuCnt + exuParameters.LduCnt,
numWirtePorts = NRIntWritePorts,
hasZero = true,
isMemRf = true
))
// backend redirect, flush pipeline
val redirect = Mux(roq.io.redirect.valid, roq.io.redirect, brq.io.redirect)
val redirectInfo = Wire(new RedirectInfo)
// exception or misprediction
redirectInfo.valid := roq.io.redirect.valid || brq.io.out.valid
redirectInfo.misPred := !roq.io.redirect.valid && brq.io.redirect.valid
redirectInfo.redirect := redirect.bits
val issueQueues = exeUnits.zipWithIndex.map({ case (eu, i) =>
def needBypass(cfg: ExuConfig): Boolean = cfg.enableBypass
val bypassCnt = exeUnits.map(_.config).count(needBypass)
def needWakeup(cfg: ExuConfig): Boolean =
(cfg.readIntRf && cfg.writeIntRf) || (cfg.readFpRf && cfg.writeFpRf)
val wakeupCnt = exeUnits.map(_.config).count(needWakeup)
assert(!(needBypass(eu.config) && !needWakeup(eu.config))) // needBypass but dont needWakeup is not allowed
val iq = Module(new IssueQueue(
eu.config,
wakeupCnt,
bypassCnt,
eu.config.enableBypass,
fifo = eu.config.supportedFuncUnits.contains(FunctionUnit.lsuCfg)
))
iq.io.redirect <> redirect
iq.io.numExist <> dispatch.io.numExist(i)
iq.io.enqCtrl <> dispatch.io.enqIQCtrl(i)
iq.io.enqData <> dispatch.io.enqIQData(i)
val wuUnitsOut = exeUnits.filter(e => needWakeup(e.config)).map(_.io.out)
for (i <- iq.io.wakeUpPorts.indices) {
iq.io.wakeUpPorts(i).bits <> wuUnitsOut(i).bits
iq.io.wakeUpPorts(i).valid := wuUnitsOut(i).valid
}
println(
s"[$i] ${eu.name} Queue wakeupCnt:$wakeupCnt bypassCnt:$bypassCnt" +
s" Supported Function:[" +
s"${
eu.config.supportedFuncUnits.map(
fu => FuType.functionNameMap(fu.fuType.litValue())).mkString(", "
)
}]"
val redirect = Mux(
roq.io.redirect.valid,
roq.io.redirect,
Mux(
brq.io.redirect.valid,
brq.io.redirect,
io.mem.replayAll
)
eu.io.in <> iq.io.deq
eu.io.redirect <> redirect
iq
})
)
io.frontend.redirect := redirect
io.frontend.redirect.valid := redirect.valid && !redirect.bits.isReplay
val memConfigs =
Seq.fill(exuParameters.LduCnt)(Exu.ldExeUnitCfg) ++
Seq.fill(exuParameters.StuCnt)(Exu.stExeUnitCfg)
val exuConfigs = exeUnits.map(_.config) ++ memConfigs
val exeWbReqs = exeUnits.map(_.io.out) ++ io.mem.ldout ++ io.mem.stout
def needWakeup(cfg: ExuConfig): Boolean =
(cfg.readIntRf && cfg.writeIntRf) || (cfg.readFpRf && cfg.writeFpRf)
def needData(a: ExuConfig, b: ExuConfig): Boolean =
(a.readIntRf && b.writeIntRf) || (a.readFpRf && b.writeFpRf)
val reservedStations = exeUnits.
zipWithIndex.
map({ case (exu, i) =>
val cfg = exu.config
val bypassQueues = issueQueues.filter(_.enableBypass)
val bypassUnits = exeUnits.filter(_.config.enableBypass)
issueQueues.foreach(iq => {
for (i <- iq.io.bypassUops.indices) {
iq.io.bypassData(i).bits := bypassUnits(i).io.out.bits
iq.io.bypassData(i).valid := bypassUnits(i).io.out.valid
val wakeUpDateVec = exuConfigs.zip(exeWbReqs).filter(x => needData(cfg, x._1)).map(_._2)
val bypassCnt = exuConfigs.count(c => c.enableBypass && needData(cfg, c))
println(s"exu:${cfg.name} wakeupCnt:${wakeUpDateVec.length} bypassCnt:$bypassCnt")
val rs = Module(new ReservationStation(
cfg, wakeUpDateVec.length, bypassCnt, cfg.enableBypass, false
))
rs.io.redirect <> redirect
rs.io.numExist <> dispatch.io.numExist(i)
rs.io.enqCtrl <> dispatch.io.enqIQCtrl(i)
rs.io.enqData <> dispatch.io.enqIQData(i)
for(
(wakeUpPort, exuOut) <-
rs.io.wakeUpPorts.zip(wakeUpDateVec)
){
wakeUpPort.bits := exuOut.bits
wakeUpPort.valid := exuOut.valid
}
exu.io.in <> rs.io.deq
exu.io.redirect <> redirect
rs
})
for( rs <- reservedStations){
rs.io.bypassUops <> reservedStations.
filter(x => x.enableBypass && needData(rs.exuCfg, x.exuCfg)).
map(_.io.selectedUop)
val bypassDataVec = exuConfigs.zip(exeWbReqs).
filter(x => x._1.enableBypass && needData(rs.exuCfg, x._1)).map(_._2)
for(i <- bypassDataVec.indices){
rs.io.bypassData(i).valid := bypassDataVec(i).valid
rs.io.bypassData(i).bits := bypassDataVec(i).bits
}
iq.io.bypassUops <> bypassQueues.map(_.io.selectedUop)
})
}
val issueQueues = exuConfigs.
zipWithIndex.
takeRight(exuParameters.LduCnt + exuParameters.StuCnt).
map({case (cfg, i) =>
val wakeUpDateVec = exuConfigs.zip(exeWbReqs).filter(x => needData(cfg, x._1)).map(_._2)
val bypassUopVec = reservedStations.
filter(r => r.exuCfg.enableBypass && needData(cfg, r.exuCfg)).map(_.io.selectedUop)
val bypassDataVec = exuConfigs.zip(exeWbReqs).
filter(x => x._1.enableBypass && needData(cfg, x._1)).map(_._2)
val iq = Module(new IssueQueue(
cfg, wakeUpDateVec.length, bypassUopVec.length
))
println(s"exu:${cfg.name} wakeupCnt:${wakeUpDateVec.length} bypassCnt:${bypassUopVec.length}")
iq.io.redirect <> redirect
iq.io.tlbFeedback := io.mem.tlbFeedback(i - exuParameters.ExuCnt + exuParameters.LduCnt + exuParameters.StuCnt)
iq.io.enq <> dispatch.io.enqIQCtrl(i)
dispatch.io.numExist(i) := iq.io.numExist
for(
(wakeUpPort, exuOut) <-
iq.io.wakeUpPorts.zip(wakeUpDateVec)
){
wakeUpPort.bits := exuOut.bits
wakeUpPort.valid := exuOut.fire() // data after arbit
}
iq.io.bypassUops <> bypassUopVec
for(i <- bypassDataVec.indices){
iq.io.bypassData(i).valid := bypassDataVec(i).valid
iq.io.bypassData(i).bits := bypassDataVec(i).bits
}
iq
})
lsuExeUnits.foreach(_.io.dmem <> io.dmem)
lsuExeUnits.foreach(_.io.scommit <> roq.io.scommit)
io.mem.mcommit := roq.io.mcommit
io.mem.ldin <> issueQueues.filter(_.exuCfg == Exu.ldExeUnitCfg).map(_.io.deq)
io.mem.stin <> issueQueues.filter(_.exuCfg == Exu.stExeUnitCfg).map(_.io.deq)
jmpExeUnit.io.exception.valid := roq.io.redirect.valid
jmpExeUnit.io.exception.bits := roq.io.exception
io.frontend.redirectInfo <> redirectInfo
io.frontend.commits <> roq.io.commits
io.frontend.outOfOrderBrInfo <> brq.io.outOfOrderBrInfo
io.frontend.inOrderBrInfo <> brq.io.inOrderBrInfo
decode.io.in <> io.frontend.cfVec
brq.io.roqRedirect <> roq.io.redirect
brq.io.memRedirect <> io.mem.replayAll
brq.io.bcommit := roq.io.bcommit
brq.io.enqReqs <> decode.io.toBrq
for ((x, y) <- brq.io.exuRedirect.zip(exeUnits.filter(_.config.hasRedirect))) {
x.bits := y.io.out.bits
x.valid := y.io.out.fire() && y.io.out.bits.redirectValid
}
decode.io.brTags <> brq.io.brTags
decBuf.io.isWalking := ParallelOR(roq.io.commits.map(c => c.valid && c.bits.isWalk)) // TODO: opt this
decBuf.io.redirect <> redirect
decBuf.io.in <> decode.io.out
rename.io.redirect <> redirect
rename.io.roqCommits <> roq.io.commits
rename.io.in <> decBuf.io.out
rename.io.intRfReadAddr <> dispatch.io.readIntRf.map(_.addr)
rename.io.fpRfReadAddr <> dispatch.io.readFpRf.map(_.addr)
rename.io.intPregRdy <> dispatch.io.intPregRdy
rename.io.fpPregRdy <> dispatch.io.fpPregRdy
rename.io.intRfReadAddr <> dispatch.io.readIntRf.map(_.addr) ++ dispatch.io.intMemRegAddr
rename.io.intPregRdy <> dispatch.io.intPregRdy ++ dispatch.io.intMemRegRdy
rename.io.fpRfReadAddr <> dispatch.io.readFpRf.map(_.addr) ++ dispatch.io.fpMemRegAddr
rename.io.fpPregRdy <> dispatch.io.fpPregRdy ++ dispatch.io.fpMemRegRdy
dispatch.io.redirect <> redirect
dispatch.io.fromRename <> rename.io.out
roq.io.memRedirect <> io.mem.replayAll
roq.io.brqRedirect <> brq.io.redirect
roq.io.dp1Req <> dispatch.io.toRoq
dispatch.io.roqIdxs <> roq.io.roqIdxs
io.mem.dp1Req <> dispatch.io.toMoq
dispatch.io.moqIdxs <> io.mem.moqIdxs
dispatch.io.commits <> roq.io.commits
intRf.io.readPorts <> dispatch.io.readIntRf
fpRf.io.readPorts <> dispatch.io.readFpRf
val exeWbReqs = exeUnits.map(_.io.out)
fpRf.io.readPorts <> dispatch.io.readFpRf ++ issueQueues.flatMap(_.io.readFpRf)
memRf.io.readPorts <> issueQueues.flatMap(_.io.readIntRf)
val wbIntIdx = exeUnits.zipWithIndex.filter(_._1.config.writeIntRf).map(_._2)
val wbFpIdx = exeUnits.zipWithIndex.filter(_._1.config.writeFpRf).map(_._2)
io.mem.redirect <> redirect
val wbu = Module(new Wbu(wbIntIdx, wbFpIdx))
val wbu = Module(new Wbu(exuConfigs))
wbu.io.in <> exeWbReqs
val wbIntResults = wbu.io.toIntRf
......@@ -158,8 +232,9 @@ class Backend(implicit val p: XSConfig) extends XSModule
rfWrite.data := x.bits.data
rfWrite
}
intRf.io.writePorts <> wbIntResults.map(exuOutToRfWrite)
val intRfWrite = wbIntResults.map(exuOutToRfWrite)
intRf.io.writePorts <> intRfWrite
memRf.io.writePorts <> intRfWrite
fpRf.io.writePorts <> wbFpResults.map(exuOutToRfWrite)
rename.io.wbIntResults <> wbIntResults
......@@ -193,7 +268,7 @@ class Backend(implicit val p: XSConfig) extends XSModule
BoringUtils.addSink(debugIntReg, "DEBUG_INT_ARCH_REG")
BoringUtils.addSink(debugFpReg, "DEBUG_FP_ARCH_REG")
val debugArchReg = WireInit(VecInit(debugIntReg ++ debugFpReg))
if (!p.FPGAPlatform) {
if (!env.FPGAPlatform) {
BoringUtils.addSource(debugArchReg, "difftestRegs")
}
......
......@@ -3,7 +3,8 @@ package xiangshan.backend.brq
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
import utils._
import chisel3.ExcitingUtils._
class BrqPtr extends XSBundle {
......@@ -52,6 +53,8 @@ object BrqPtr {
class BrqIO extends XSBundle{
// interrupt/exception happen, flush Brq
val roqRedirect = Input(Valid(new Redirect))
// mem replay
val memRedirect = Input(Valid(new Redirect))
// receive branch/jump calculated target
val exuRedirect = Vec(exuParameters.AluCnt + exuParameters.JmpCnt, Flipped(ValidIO(new ExuOutput)))
// from decode, branch insts enq
......@@ -62,18 +65,19 @@ class BrqIO extends XSBundle{
val out = ValidIO(new ExuOutput)
// misprediction, flush pipeline
val redirect = Output(Valid(new Redirect))
val outOfOrderBrInfo = ValidIO(new BranchUpdateInfo)
// commit cnt of branch instr
val bcommit = Input(UInt(BrTagWidth.W))
// in order dequeue to train bpd
val inOrderBrInfo = ValidIO(new BranchUpdateInfo)
}
class Brq extends XSModule {
val io = IO(new BrqIO)
def redirctWindowSize: Int = BrqSize/2
require(redirctWindowSize <= BrqSize && redirctWindowSize > 0)
class BrqEntry extends Bundle {
val ptrFlag = Bool()
val npc = UInt(VAddrBits.W)
val misPred = Bool()
val exuOut = new ExuOutput
}
......@@ -86,6 +90,7 @@ class Brq extends XSModule {
val isIdle = Bool()
}
val brCommitCnt = RegInit(0.U(BrTagWidth.W))
val brQueue = Reg(Vec(BrqSize, new BrqEntry))
val stateQueue = RegInit(VecInit(Seq.fill(BrqSize)(s_idle)))
......@@ -97,34 +102,67 @@ class Brq extends XSModule {
// dequeue
val headIdx = headPtr.value
var commitIdx = WireInit(headIdx)
def needCheckNext(idx: UInt): Bool = {
(stateQueue(idx).isWb && !brQueue(idx).misPred) || stateQueue(idx).isCommit
val skipMask = Cat(stateQueue.zipWithIndex.map({
case (s, i) => (s.isWb && !brQueue(i).exuOut.brUpdate.isMisPred) || s.isCommit
}).reverse)
/*
example: headIdx = 2
headIdxOH = 00000100
headIdxMaskHI = 11111100
headIdxMaskLo = 00000011
skipMask = 00111101
commitIdxHi = 6
commitIdxLo = 0
commitIdx = 6
*/
val headIdxOH = UIntToOH(headIdx)
val headIdxMaskHiVec = Wire(Vec(BrqSize, Bool()))
for(i <- headIdxMaskHiVec.indices){
headIdxMaskHiVec(i) := { if(i==0) headIdxOH(i) else headIdxMaskHiVec(i-1) || headIdxOH(i) }
}
val headIdxMaskHi = headIdxMaskHiVec.asUInt()
val headIdxMaskLo = (~headIdxMaskHi).asUInt()
val commitIdxHi = PriorityEncoder((~skipMask).asUInt() & headIdxMaskHi)
val (commitIdxLo, findLo) = PriorityEncoderWithFlag((~skipMask).asUInt() & headIdxMaskLo)
val skipHi = (skipMask | headIdxMaskLo) === Fill(BrqSize, 1.U(1.W))
val useLo = skipHi && findLo
var checkNext = WireInit(needCheckNext(headIdx))
for(i <- 1 until redirctWindowSize){
val idx = commitIdx + i.U
val commitThis = checkNext && stateQueue(idx).isWb && brQueue(idx).misPred
commitIdx = Mux(commitThis,
idx,
commitIdx
val commitIdx = Mux(stateQueue(commitIdxHi).isWb && brQueue(commitIdxHi).exuOut.brUpdate.isMisPred,
commitIdxHi,
Mux(useLo && stateQueue(commitIdxLo).isWb && brQueue(commitIdxLo).exuOut.brUpdate.isMisPred,
commitIdxLo,
headIdx
)
checkNext = checkNext && needCheckNext(idx)
}
)
val commitIsHead = commitIdx===headIdx
val deqValid = !stateQueue(headIdx).isIdle && commitIsHead
val deqValid = !stateQueue(headIdx).isIdle && commitIsHead && 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 := deqValid
io.inOrderBrInfo.bits := commitEntry.exuOut.brUpdate
// XSDebug(
// p"commitIdxHi:$commitIdxHi ${Binary(headIdxMaskHi)} ${Binary(skipMask)}\n"
// )
// XSDebug(
// p"commitIdxLo:$commitIdxLo ${Binary(headIdxMaskLo)} ${Binary(skipMask)}\n"
// )
XSDebug(p"headIdx:$headIdx commitIdx:$commitIdx\n")
XSDebug(p"headPtr:$headPtr tailPtr:$tailPtr\n")
XSDebug("")
stateQueue.map(s =>{
stateQueue.reverse.map(s =>{
XSDebug(false, s.isIdle, "-")
XSDebug(false, s.isWb, "w")
XSDebug(false, s.isCommit, "c")
......@@ -141,10 +179,16 @@ class Brq extends XSModule {
)
headPtr := headPtrNext
io.redirect.valid := commitValid && commitEntry.misPred
io.redirect.valid := commitValid &&
commitIsMisPred &&
!io.roqRedirect.valid &&
!io.redirect.bits.needFlush(io.memRedirect)
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
XSInfo(io.out.valid,
p"commit branch to roq, mispred:${io.redirect.valid} pc=${Hexadecimal(io.out.bits.uop.cf.pc)}\n"
)
......@@ -155,11 +199,11 @@ class Brq extends XSModule {
for((enq, brTag) <- io.enqReqs.zip(io.brTags)){
enq.ready := !full
brTag := tailPtrNext
// TODO: check rvc and use predict npc
when(enq.fire()){
brQueue(tailPtrNext.value).npc := enq.bits.cf.pc + 4.U
brQueue(tailPtrNext.value).npc := enq.bits.cf.brUpdate.pnpc
brQueue(tailPtrNext.value).ptrFlag := tailPtrNext.flag
}
tailPtrNext = tailPtrNext + enq.fire()
full = isFull(tailPtrNext, headPtrNext)
}
......@@ -174,8 +218,11 @@ class Brq extends XSModule {
p" pc=${Hexadecimal(exuWb.bits.uop.cf.pc)} pnpc=${Hexadecimal(brQueue(wbIdx).npc)} target=${Hexadecimal(exuWb.bits.redirect.target)}\n"
)
stateQueue(wbIdx) := s_wb
brQueue(wbIdx).exuOut := exuWb.bits
brQueue(wbIdx).misPred := brQueue(wbIdx).npc =/= exuWb.bits.redirect.target
val exuOut = WireInit(exuWb.bits)
val isMisPred = brQueue(wbIdx).npc =/= exuWb.bits.redirect.target
exuOut.redirect.isMisPred := isMisPred
exuOut.brUpdate.isMisPred := isMisPred
brQueue(wbIdx).exuOut := exuOut
}
}
......@@ -184,15 +231,21 @@ class Brq extends XSModule {
stateQueue.foreach(_ := s_idle)
headPtr := BrqPtr(false.B, 0.U)
tailPtr := BrqPtr(false.B, 0.U)
}.elsewhen(io.redirect.valid){
// misprediction
brCommitCnt := 0.U
}.elsewhen(io.redirect.valid || io.memRedirect.valid){
// misprediction or replay
stateQueue.zipWithIndex.foreach({case(s, i) =>
val ptr = BrqPtr(brQueue(i).ptrFlag, i.U)
when(ptr.needBrFlush(io.redirect.bits.brTag)){
when(
(io.redirect.valid && ptr.needBrFlush(io.redirect.bits.brTag)) ||
(s.isWb && brQueue(i).exuOut.uop.needFlush(io.memRedirect))
){
s := s_idle
}
})
tailPtr := io.redirect.bits.brTag + true.B
when(io.redirect.valid){ // Only Br Mispred reset tailPtr, replay does not
tailPtr := io.redirect.bits.brTag + true.B
}
}
......@@ -212,5 +265,43 @@ class Brq extends XSModule {
}
XSInfo(debug_roq_redirect, "roq redirect, flush brq\n")
XSInfo(debug_brq_redirect, p"brq redirect, target:${Hexadecimal(io.redirect.bits.target)} flptr:${io.redirect.bits.freelistAllocPtr}\n")
XSInfo(debug_brq_redirect, p"brq redirect, target:${Hexadecimal(io.redirect.bits.target)}\n")
val fire = io.out.fire()
val predRight = fire && !commitIsMisPred
val predWrong = fire && commitIsMisPred
// val isBType = commitEntry.exuOut.brUpdate.btbType===BTBtype.B
val isBType = commitEntry.exuOut.brUpdate.pd.isBr
// val isJType = commitEntry.exuOut.brUpdate.btbType===BTBtype.J
val isJType = commitEntry.exuOut.brUpdate.pd.isJal
// val isIType = commitEntry.exuOut.brUpdate.btbType===BTBtype.I
val isIType = commitEntry.exuOut.brUpdate.pd.isJalr
// val isRType = commitEntry.exuOut.brUpdate.btbType===BTBtype.R
val isRType = commitEntry.exuOut.brUpdate.pd.isRet
val mbpInstr = fire
val mbpRight = predRight
val mbpWrong = predWrong
val mbpBRight = predRight && isBType
val mbpBWrong = predWrong && isBType
val mbpJRight = predRight && isJType
val mbpJWrong = predWrong && isJType
val mbpIRight = predRight && isIType
val mbpIWrong = predWrong && isIType
val mbpRRight = predRight && isRType
val mbpRWrong = predWrong && isRType
if(!env.FPGAPlatform){
ExcitingUtils.addSource(mbpInstr, "perfCntCondMbpInstr", Perf)
ExcitingUtils.addSource(mbpRight, "perfCntCondMbpRight", Perf)
ExcitingUtils.addSource(mbpWrong, "perfCntCondMbpWrong", Perf)
ExcitingUtils.addSource(mbpBRight, "perfCntCondMbpBRight", Perf)
ExcitingUtils.addSource(mbpBWrong, "perfCntCondMbpBWrong", Perf)
ExcitingUtils.addSource(mbpJRight, "perfCntCondMbpJRight", Perf)
ExcitingUtils.addSource(mbpJWrong, "perfCntCondMbpJWrong", Perf)
ExcitingUtils.addSource(mbpIRight, "perfCntCondMbpIRight", Perf)
ExcitingUtils.addSource(mbpIWrong, "perfCntCondMbpIWrong", Perf)
ExcitingUtils.addSource(mbpRRight, "perfCntCondMbpRRight", Perf)
ExcitingUtils.addSource(mbpRWrong, "perfCntCondMbpRWrong", Perf)
}
}
......@@ -3,10 +3,11 @@ package xiangshan.backend.decode
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
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))
......@@ -21,9 +22,9 @@ class DecodeBuffer extends XSModule {
case (v, fire) =>
!v || fire
})
).asBool()
)
val rightRdyVec = io.out.map(_.ready && leftCanIn)
val flush = io.redirect.valid && !io.redirect.bits.isReplay
for( i <- 0 until RenameWidth){
when(io.out(i).fire()){
......@@ -32,21 +33,31 @@ class DecodeBuffer extends XSModule {
when(io.in(i).fire()){
validVec(i) := true.B
}
when(io.redirect.valid){
when(flush){
validVec(i) := false.B
}
io.in(i).ready := rightRdyVec(i)
io.out(i).bits <> RegEnable(io.in(i).bits, io.in(i).fire())
io.out(i).valid := validVec(i) && !io.redirect.valid
val r = RegEnable(io.in(i).bits, io.in(i).fire())
io.in(i).ready := leftCanIn
io.out(i).bits <> r
if(i > 0 ){
io.out(i).valid := validVec(i) &&
!flush &&
Mux(r.ctrl.noSpecExec,
!ParallelOR(validVec.take(i)),
!ParallelOR(io.out.zip(validVec).take(i).map(x => x._2 && x._1.bits.ctrl.noSpecExec))
) && !io.isWalking
} else {
require( i == 0)
io.out(i).valid := validVec(i) && !flush && !io.isWalking
}
}
for(in<- io.in){
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")
}
XSDebug(p"validVec: ${Binary(validVec.asUInt())}\n")
}
package xiangshan.backend.decode
import chisel3._
import chisel3.util._
import xiangshan.{FuType, HasXSParameter}
import xiangshan.backend._
import xiangshan.backend.decode.isa._
trait HasInstrType {
def InstrN = "b0000".U
def InstrI = "b0100".U
def InstrR = "b0101".U
def InstrS = "b0010".U
def InstrB = "b0001".U
def InstrU = "b0110".U
def InstrJ = "b0111".U
def InstrA = "b1110".U
def InstrSA = "b1111".U // Atom Inst: SC
def isrfWen(instrType : UInt): Bool = instrType(2)
// TODO: optimize these encoding
def InstrN = "b0000".U
def InstrI = "b0001".U
def InstrR = "b0010".U
def InstrS = "b0011".U
def InstrB = "b0100".U
def InstrU = "b0101".U
def InstrJ = "b0110".U
def InstrA = "b0111".U
def InstrSA = "b1000".U // Atom Inst: SC
def InstrFR = "b1001".U
def InstrFI = "b1010".U // flw/fld
def InstrGtoF = "b1011".U
def InstrFS = "b1100".U
def InstrFtoG = "b1101".U
def isrfWen(instrType : UInt): Bool = Array(
InstrI, InstrR, InstrU, InstrJ, InstrA, InstrSA, InstrFtoG
).map(_===instrType).reduce(_||_)
def isfpWen(instrType: UInt): Bool = Array(
InstrFI, InstrFR, InstrGtoF
).map(_===instrType).reduce(_||_)
}
object SrcType {
......@@ -36,13 +48,20 @@ object FuOpType {
object Instructions extends HasInstrType with HasXSParameter {
def NOP = 0x00000013.U
val DecodeDefault = List(InstrN, FuType.alu, ALUOpType.sll)
def DecodeTable = RVIInstr.table ++ XSTrap.table ++
(if (HasMExtension) RVMInstr.table else Nil) // ++
def DecodeTable =
RVIInstr.table ++
XSTrap.table ++
RVZicsrInstr.table ++
RVZifenceiInstr.table ++
Privileged.table ++
RVFInstr.table ++
RVDInstr.table ++
(if (HasMExtension) RVMInstr.table else Nil) // ++
// (if (HasCExtension) RVCInstr.table else Nil) ++
// (if (HasFPU) RVFInstr.table ++ RVDInstr.table else Nil) ++
// Privileged.table ++
// RVAInstr.table ++
// RVZicsrInstr.table ++ RVZifenceiInstr.table
// RVZicsrInstr.table
}
object CInstructions extends HasInstrType with HasXSParameter {
......
......@@ -4,7 +4,7 @@ import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.backend.brq.BrqPtr
import xiangshan.utils._
import utils._
class DecodeStage extends XSModule {
val io = IO(new Bundle() {
......@@ -34,24 +34,20 @@ class DecodeStage extends XSModule {
for (i <- 0 until DecodeWidth) {
decoders(i).io.in <> io.in(i).bits
decoderToBrq(i) := decoders(i).io.out // CfCtrl without bfTag and brMask
// send CfCtrl without brTags and brMasks to brq
io.toBrq(i).valid := io.in(i).valid && io.out(i).ready && decoders(i).io.out.cf.isBr
XSDebug(io.toBrq(i).valid && io.toBrq(i).ready, p"Branch instr detected. Sending it to BRQ.\n")
XSDebug(io.toBrq(i).valid && !io.toBrq(i).ready, p"Branch instr detected. BRQ full...waiting\n")
XSDebug(io.in(i).valid && !io.out(i).ready, p"DecBuf full...waiting\n")
decoderToBrq(i).brTag := DontCare
io.toBrq(i).bits := decoderToBrq(i)
// if brq returns ready, then assert valid and send CfCtrl with bfTag and brMask to DecBuffer
io.out(i).valid := io.toBrq(i).ready && io.in(i).valid
XSDebug(io.out(i).valid && decoders(i).io.out.cf.isBr && io.out(i).ready, p"Sending branch instr to DecBuf\n")
XSDebug(io.out(i).valid && !decoders(i).io.out.cf.isBr && io.out(i).ready, p"Sending non-branch instr to DecBuf\n")
decoderToDecBuffer(i) := decoders(i).io.out
decoderToDecBuffer(i).brTag := io.brTags(i)
io.out(i).bits := decoderToDecBuffer(i)
// If an instruction i is received by DecBuffer,
// then assert in(i).ready, waiting for new instructions
// Only when all out(i).ready signals are true can we decode next instruction group (?)
io.in(i).ready := io.out(i).ready
val thisReady = io.out(i).ready && io.toBrq(i).ready
val thisBrqValid = io.in(i).valid && !decoders(i).io.out.cf.brUpdate.pd.notCFI && io.out(i).ready
val thisOutValid = io.in(i).valid && io.toBrq(i).ready
io.in(i).ready := { if (i == 0) thisReady else io.in(i-1).ready && thisReady }
io.out(i).valid := { if (i == 0) thisOutValid else io.in(i-1).ready && thisOutValid }
io.toBrq(i).valid := { if (i == 0) thisBrqValid else io.in(i-1).ready && thisBrqValid }
XSDebug(io.in(i).valid || io.out(i).valid || io.toBrq(i).valid, "i:%d In(%d %d) Out(%d %d) ToBrq(%d %d) pc:%x instr:%x\n", i.U, io.in(i).valid, io.in(i).ready, io.out(i).valid, io.out(i).ready, io.toBrq(i).valid, io.toBrq(i).ready, io.in(i).bits.pc, io.in(i).bits.instr)
}
}
\ No newline at end of file
......@@ -16,154 +16,126 @@ class Decoder extends XSModule with HasInstrType {
val out = Output(new CfCtrl)
})
io.out := DontCare // FIXME: remove me!!!
io.out.cf := io.in
val hasIntr = Wire(Bool())
val instr: UInt = io.in.instr
val decodeList = ListLookup(instr, Instructions.DecodeDefault, Instructions.DecodeTable)
val instrType :: fuType :: fuOpType :: Nil = decodeList
// todo: remove this when fetch stage can decide if an instr is br/jmp
io.out.cf.isBr := (instrType === InstrB ||
(fuOpType === BRUOpType.jal && instrType === InstrJ && fuType === FuType.jmp) ||
(fuOpType === BRUOpType.jalr && instrType === InstrI && fuType === FuType.jmp))
// val isRVC = instr(1, 0) =/= "b11".U
// val rvcImmType :: rvcSrc1Type :: rvcSrc2Type :: rvcDestType :: Nil =
// ListLookup(instr, CInstructions.DecodeDefault, CInstructions.CExtraDecodeTable)
// io.out.cf.brUpdate.isBr := (instrType === InstrB ||
// (fuOpType === JumpOpType.jal && instrType === InstrJ && fuType === FuType.jmp) ||
// (fuOpType === JumpOpType.jalr && instrType === InstrI && fuType === FuType.jmp) ||
// (fuOpType === CSROpType.jmp && instrType === InstrI && fuType === FuType.csr))
val isRVC = instr(1, 0) =/= "b11".U
val rvcImmType :: rvcSrc1Type :: rvcSrc2Type :: rvcDestType :: Nil =
ListLookup(instr, CInstructions.DecodeDefault, CInstructions.CExtraDecodeTable)
io.out.ctrl.fuOpType := fuOpType
io.out.ctrl.fuType := fuType
val SrcTypeTable = List(
InstrI -> (SrcType.reg, SrcType.imm),
InstrR -> (SrcType.reg, SrcType.reg),
InstrS -> (SrcType.reg, SrcType.reg),
InstrSA-> (SrcType.reg, SrcType.reg),
InstrB -> (SrcType.reg, SrcType.reg),
InstrU -> (SrcType.pc , SrcType.imm),
InstrJ -> (SrcType.pc , SrcType.imm),
InstrN -> (SrcType.pc , SrcType.imm)
InstrI -> (SrcType.reg, SrcType.imm),
InstrFI -> (SrcType.reg, SrcType.imm),
InstrR -> (SrcType.reg, SrcType.reg),
InstrS -> (SrcType.reg, SrcType.reg),
InstrFS -> (SrcType.reg, SrcType.fp ),
InstrSA -> (SrcType.reg, SrcType.reg),
InstrB -> (SrcType.reg, SrcType.reg),
InstrU -> (SrcType.pc , SrcType.imm),
InstrJ -> (SrcType.pc , SrcType.imm),
InstrN -> (SrcType.pc , SrcType.imm)
)
val src1Type = LookupTree(instrType, SrcTypeTable.map(p => (p._1, p._2._1)))
val src2Type = LookupTree(instrType, SrcTypeTable.map(p => (p._1, p._2._2)))
val (rs, rt, rd) = (instr(19, 15), instr(24, 20), instr(11, 7))
// see riscv-spec vol1, Table 16.1: Compressed 16-bit RVC instruction formats.
val rs1 = instr(11,7)
val rs2 = instr(6,2)
// val rs1p = LookupTree(instr(9,7), RVCInstr.RVCRegNumTable.map(p => (p._1, p._2)))
// val rs2p = LookupTree(instr(4,2), RVCInstr.RVCRegNumTable.map(p => (p._1, p._2)))
// val rvc_shamt = Cat(instr(12),instr(6,2))
// val rdp_rs1p = LookupTree(instr(9,7), RVCRegNumTable)
// val rdp = LookupTree(instr(4,2), RVCRegNumTable)
// val RegLookUpTable = List(
// RVCInstr.DtCare -> 0.U,
// RVCInstr.REGrs -> rs,
// RVCInstr.REGrt -> rt,
// RVCInstr.REGrd -> rd,
// RVCInstr.REGrs1 -> rs1,
// RVCInstr.REGrs2 -> rs2,
// RVCInstr.REGrs1p -> rs1p,
// RVCInstr.REGrs2p -> rs2p,
// RVCInstr.REGx1 -> 1.U,
// RVCInstr.REGx2 -> 2.U
// )
// val rvc_src1 = LookupTree(rvcSrc1Type, RegLookUpTable.map(p => (p._1, p._2)))
// val rvc_src2 = LookupTree(rvcSrc2Type, RegLookUpTable.map(p => (p._1, p._2)))
// val rvc_dest = LookupTree(rvcDestType, RegLookUpTable.map(p => (p._1, p._2)))
// val rfSrc1 = Mux(isRVC, rvc_src1, rs)
// val rfSrc2 = Mux(isRVC, rvc_src2, rt)
// val rfDest = Mux(isRVC, rvc_dest, rd)
val rs1p = LookupTree(instr(9,7), RVCInstr.RVCRegNumTable.map(p => (p._1, p._2)))
val rs2p = LookupTree(instr(4,2), RVCInstr.RVCRegNumTable.map(p => (p._1, p._2)))
val rvc_shamt = Cat(instr(12),instr(6,2))
val RegLookUpTable = List(
RVCInstr.DtCare -> 0.U,
RVCInstr.REGrs -> rs,
RVCInstr.REGrt -> rt,
RVCInstr.REGrd -> rd,
RVCInstr.REGrs1 -> rs1,
RVCInstr.REGrs2 -> rs2,
RVCInstr.REGrs1p -> rs1p,
RVCInstr.REGrs2p -> rs2p,
RVCInstr.REGx1 -> 1.U,
RVCInstr.REGx2 -> 2.U
)
val rvc_src1 = LookupTree(rvcSrc1Type, RegLookUpTable.map(p => (p._1, p._2)))
val rvc_src2 = LookupTree(rvcSrc2Type, RegLookUpTable.map(p => (p._1, p._2)))
val rvc_dest = LookupTree(rvcDestType, RegLookUpTable.map(p => (p._1, p._2)))
val rfSrc1 = Mux(isRVC, rvc_src1, rs)
val rfSrc2 = Mux(isRVC, rvc_src2, rt)
val rfDest = Mux(isRVC, rvc_dest, rd)
// TODO: refactor decode logic
// make non-register addressing to zero, since isu.sb.isBusy(0) === false.B
io.out.ctrl.lsrc1 := Mux(src1Type === SrcType.pc, 0.U, rs)
io.out.ctrl.lsrc2 := Mux(src2Type === SrcType.reg, rt, 0.U)
io.out.ctrl.rfWen := isrfWen(instrType)
io.out.ctrl.ldest := Mux(isrfWen(instrType), rd, 0.U)
val rfWen = isrfWen(instrType)
val fpWen = isfpWen(instrType)
io.out.ctrl.lsrc1 := Mux(src1Type === SrcType.pc, 0.U, rfSrc1)
io.out.ctrl.lsrc2 := Mux(src2Type === SrcType.imm, 0.U, rfSrc2)
io.out.ctrl.rfWen := rfWen
io.out.ctrl.fpWen := fpWen
io.out.ctrl.ldest := Mux(fpWen || rfWen, rfDest, 0.U)
// io.out.bits.data := DontCare
val imm = LookupTree(instrType, List(
InstrI -> SignExt(instr(31, 20), XLEN),
InstrFI -> SignExt(instr(31, 20), XLEN),
InstrS -> SignExt(Cat(instr(31, 25), instr(11, 7)), XLEN),
InstrFS -> SignExt(Cat(instr(31, 25), instr(11, 7)), XLEN),
InstrSA -> SignExt(Cat(instr(31, 25), instr(11, 7)), XLEN),
InstrB -> SignExt(Cat(instr(31), instr(7), instr(30, 25), instr(11, 8), 0.U(1.W)), XLEN),
InstrU -> SignExt(Cat(instr(31, 12), 0.U(12.W)), XLEN),//fixed
InstrJ -> SignExt(Cat(instr(31), instr(19, 12), instr(20), instr(30, 21), 0.U(1.W)), XLEN)
))
// val immrvc = LookupTree(rvcImmType, List(
// // InstrIW -> Cat(Fill(20+32, instr(31)), instr(31, 20)),//fixed
// RVCInstr.ImmNone -> 0.U(XLEN.W),
// RVCInstr.ImmLWSP -> ZeroExt(Cat(instr(3,2), instr(12), instr(6,4), 0.U(2.W)), XLEN),
// RVCInstr.ImmLDSP -> ZeroExt(Cat(instr(4,2), instr(12), instr(6,5), 0.U(3.W)), XLEN),
// RVCInstr.ImmSWSP -> ZeroExt(Cat(instr(8,7), instr(12,9), 0.U(2.W)), XLEN),
// RVCInstr.ImmSDSP -> ZeroExt(Cat(instr(9,7), instr(12,10), 0.U(3.W)), XLEN),
// RVCInstr.ImmSW -> ZeroExt(Cat(instr(5), instr(12,10), instr(6), 0.U(2.W)), XLEN),
// RVCInstr.ImmSD -> ZeroExt(Cat(instr(6,5), instr(12,10), 0.U(3.W)), XLEN),
// RVCInstr.ImmLW -> ZeroExt(Cat(instr(5), instr(12,10), instr(6), 0.U(2.W)), XLEN),
// RVCInstr.ImmLD -> ZeroExt(Cat(instr(6,5), instr(12,10), 0.U(3.W)), XLEN),
// RVCInstr.ImmJ -> SignExt(Cat(instr(12), instr(8), instr(10,9), instr(6), instr(7), instr(2), instr(11), instr(5,3), 0.U(1.W)), XLEN),
// RVCInstr.ImmB -> SignExt(Cat(instr(12), instr(6,5), instr(2), instr(11,10), instr(4,3), 0.U(1.W)), XLEN),
// RVCInstr.ImmLI -> SignExt(Cat(instr(12), instr(6,2)), XLEN),
// RVCInstr.ImmLUI -> SignExt(Cat(instr(12), instr(6,2), 0.U(12.W)), XLEN),
// RVCInstr.ImmADDI -> SignExt(Cat(instr(12), instr(6,2)), XLEN),
// RVCInstr.ImmADDI16SP-> SignExt(Cat(instr(12), instr(4,3), instr(5), instr(2), instr(6), 0.U(4.W)), XLEN),
// RVCInstr.ImmADD4SPN-> ZeroExt(Cat(instr(10,7), instr(12,11), instr(5), instr(6), 0.U(2.W)), XLEN)
// // ImmFLWSP ->
// // ImmFLDSP ->
// ))
// io.out.ctrl.imm := Mux(isRVC, immrvc, imm)
io.out.ctrl.imm := imm
// when (fuType === FuType.bru) {
// def isLink(reg: UInt) = (reg === 1.U || reg === 5.U)
//// when (isLink(rd) && fuOpType === BRUOpType.jal) { io.out.ctrl.fuOpType := ALUOpType.call }
// when (fuOpType === BRUOpType.jalr) {
//// when (isLink(rs)) { io.out.ctrl.fuOpType := ALUOpType.ret }
//// when (isLink(rt)) { io.out.ctrl.fuOpType := ALUOpType.call }
// }
// }
val immrvc = LookupTree(instrType, List(
RVCInstr.ImmNone -> 0.U(XLEN.W),
RVCInstr.ImmLWSP -> ZeroExt(Cat(instr(3,2), instr(12), instr(6,4), 0.U(2.W)), XLEN),
RVCInstr.ImmLDSP -> ZeroExt(Cat(instr(4,2), instr(12), instr(6,5), 0.U(3.W)), XLEN),
RVCInstr.ImmSWSP -> ZeroExt(Cat(instr(8,7), instr(12,9), 0.U(2.W)), XLEN),
RVCInstr.ImmSDSP -> ZeroExt(Cat(instr(9,7), instr(12,10), 0.U(3.W)), XLEN),
RVCInstr.ImmSW -> ZeroExt(Cat(instr(5), instr(12,10), instr(6), 0.U(2.W)), XLEN),
RVCInstr.ImmSD -> ZeroExt(Cat(instr(6,5), instr(12,10), 0.U(3.W)), XLEN),
RVCInstr.ImmLW -> ZeroExt(Cat(instr(5), instr(12,10), instr(6), 0.U(2.W)), XLEN),
RVCInstr.ImmLD -> ZeroExt(Cat(instr(6,5), instr(12,10), 0.U(3.W)), XLEN),
RVCInstr.ImmJ -> SignExt(Cat(instr(12), instr(8), instr(10,9), instr(6), instr(7), instr(2), instr(11), instr(5,3), 0.U(1.W)), XLEN),
RVCInstr.ImmB -> SignExt(Cat(instr(12), instr(6,5), instr(2), instr(11,10), instr(4,3), 0.U(1.W)), XLEN),
RVCInstr.ImmLI -> SignExt(Cat(instr(12), instr(6,2)), XLEN),
RVCInstr.ImmLUI -> SignExt(Cat(instr(12), instr(6,2), 0.U(12.W)), XLEN),
RVCInstr.ImmADDI -> SignExt(Cat(instr(12), instr(6,2)), XLEN),
RVCInstr.ImmADDI16SP-> SignExt(Cat(instr(12), instr(4,3), instr(5), instr(2), instr(6), 0.U(4.W)), XLEN),
RVCInstr.ImmADD4SPN-> ZeroExt(Cat(instr(10,7), instr(12,11), instr(5), instr(6), 0.U(2.W)), XLEN)
))
io.out.ctrl.imm := Mux(isRVC, immrvc, imm)
when (fuType === FuType.jmp) {
def isLink(reg: UInt) = (reg === 1.U || reg === 5.U)
when (isLink(rd) && fuOpType === JumpOpType.jal) { io.out.ctrl.fuOpType := JumpOpType.call }
when (fuOpType === JumpOpType.jalr) {
when (isLink(rs)) { io.out.ctrl.fuOpType := JumpOpType.ret }
when (isLink(rd)) { io.out.ctrl.fuOpType := JumpOpType.call }
}
}
// fix LUI
io.out.ctrl.src1Type := Mux(instr(6,0) === "b0110111".U, SrcType.reg, src1Type)
io.out.ctrl.src2Type := src2Type
val NoSpecList = Seq(
// FuType.csr,
// FuType.mou
)
val BlockList = Seq(
)
io.out.ctrl.noSpecExec := NoSpecList.map(j => io.out.ctrl.fuType === j).foldRight(false.B)((sum, i) => sum | i)
io.out.ctrl.isBlocked := DontCare
// (
// io.out.ctrl.fuType === (FuType.ldu | FuType.stu) && LSUOpType.isAtom(io.out.ctrl.fuOpType) ||
// BlockList.map(j => io.out.ctrl.fuType === j).foldRight(false.B)((sum, i) => sum | i)
// )
//output signals
// Debug(){
// when(io.out.fire()){printf("[IDU] issue: pc %x npc %x instr %x\n", io.out.bits.cf.pc, io.out.bits.cf.pnpc, io.out.bits.cf.instr)}
// }
//FIXME: move it to ROB
val intrVec = WireInit(0.U(12.W))
BoringUtils.addSink(intrVec, "intrVecIDU")
io.out.cf.intrVec.zip(intrVec.asBools).map{ case(x, y) => x := y }
hasIntr := intrVec.orR
val vmEnable = WireInit(false.B)
BoringUtils.addSink(vmEnable, "DTLBENABLE")
io.out.cf.exceptionVec.map(_ := false.B)
io.out.cf.exceptionVec(illegalInstr) := (instrType === InstrN && !hasIntr)
io.out.cf.exceptionVec(illegalInstr) := instrType === InstrN
io.out.cf.exceptionVec(instrPageFault) := io.in.exceptionVec(instrPageFault)
io.out.cf.exceptionVec(instrAccessFault) := io.in.pc(VAddrBits - 1, PAddrBits).orR && !vmEnable
......@@ -171,6 +143,5 @@ class Decoder extends XSModule with HasInstrType {
when(io.out.ctrl.isXSTrap){
io.out.ctrl.lsrc1 := 10.U // a0
}
// io.isWFI := (instr === Priviledged.WFI) && io.in.valid
io.out.ctrl.noSpecExec := io.out.ctrl.isXSTrap || io.out.ctrl.fuType===FuType.csr
}
......@@ -3,6 +3,7 @@ package xiangshan.backend.decode.isa
import chisel3._
import chisel3.util._
import xiangshan.FuType
import xiangshan.backend._
import xiangshan.backend.decode.HasInstrType
......@@ -15,5 +16,14 @@ object Privileged extends HasInstrType {
def WFI = BitPat("b0001000_00101_00000_000_00000_1110011")
// fixme: add privilege inst
val table = Array()
val table = Array(
ECALL -> List(InstrI, FuType.csr, CSROpType.jmp),
MRET -> List(InstrI, FuType.csr, CSROpType.jmp),
SRET -> List(InstrI, FuType.csr, CSROpType.jmp)
// SFANCE_VMA -> List(InstrR, FuType.mou, MOUOpType.sfence_vma),
// FENCE -> List(InstrS, FuType.alu, ALUOpType.add), // nop InstrS -> !wen
// WFI -> List(InstrI, FuType.alu, ALUOpType.add) // nop
// FENCE -> List(InstrB, FuType.mou, MOUOpType.fencei)
)
}
......@@ -5,6 +5,7 @@ import chisel3._
import chisel3.util._
import xiangshan.backend.decode.HasInstrType
import xiangshan.FuType
import xiangshan.backend._
trait HasRVCConst {
......@@ -117,8 +118,49 @@ object RVCInstr extends HasInstrType with HasRVCConst {
// def is_C_ADDI4SPN(op: UInt) = op(12,5) =/= 0.U
// fixme: add rvc inst
val table = Array()
val table = Array(
C_ILLEGAL -> List(InstrN, FuType.csr, CSROpType.jmp),
C_ADDI4SPN -> List(InstrI, FuType.alu, ALUOpType.add),
C_FLD -> List(InstrFI, FuType.ldu, LSUOpType.ld),
C_LW -> List(InstrI, FuType.ldu, LSUOpType.lw),
C_LD -> List(InstrI, FuType.ldu, LSUOpType.ld),
C_FSD -> List(InstrFS, FuType.stu, LSUOpType.sd),
C_SW -> List(InstrS, FuType.stu, LSUOpType.sw),
C_SD -> List(InstrS, FuType.stu, LSUOpType.sd),
C_NOP -> List(InstrI, FuType.alu, ALUOpType.add),
C_ADDI -> List(InstrI, FuType.alu, ALUOpType.add),
// C_JAL -> List(InstrI, FuType.alu, ALUOpType.add),//RV32C only
C_ADDIW -> List(InstrI, FuType.alu, ALUOpType.addw),
C_LI -> List(InstrI, FuType.alu, ALUOpType.add),
C_ADDI16SP -> List(InstrI, FuType.alu, ALUOpType.add),
C_LUI -> List(InstrU, FuType.alu, ALUOpType.add),
C_SRLI -> List(InstrI, FuType.alu, ALUOpType.srl),
C_SRAI -> List(InstrI, FuType.alu, ALUOpType.sra),
C_ANDI -> List(InstrI, FuType.alu, ALUOpType.and),
C_SUB -> List(InstrR, FuType.alu, ALUOpType.sub),
C_XOR -> List(InstrR, FuType.alu, ALUOpType.xor),
C_OR -> List(InstrR, FuType.alu, ALUOpType.or),
C_AND -> List(InstrR, FuType.alu, ALUOpType.and),
C_SUBW -> List(InstrR, FuType.alu, ALUOpType.subw),
C_ADDW -> List(InstrR, FuType.alu, ALUOpType.addw),
C_J -> List(InstrJ, FuType.jmp, JumpOpType.jal),
C_BEQZ -> List(InstrB, FuType.alu, ALUOpType.beq),
C_BNEZ -> List(InstrB, FuType.alu, ALUOpType.bne),
C_SLLI -> List(InstrI, FuType.alu, ALUOpType.sll),
// C_FLDSP -> List(InstrI, FuType.alu, ALUOpType.add),
C_LWSP -> List(InstrI, FuType.ldu, LSUOpType.lw),
// C_FLWSP -> List(InstrI, FuType.alu, ALUOpType.add),
C_LDSP -> List(InstrI, FuType.ldu, LSUOpType.ld),
C_JR -> List(InstrI, FuType.jmp, JumpOpType.jalr),
C_MV -> List(InstrR, FuType.alu, ALUOpType.add),
C_EBREAK -> List(InstrI, FuType.alu, ALUOpType.add),
C_JALR -> List(InstrI, FuType.jmp, JumpOpType.jalr),
C_ADD -> List(InstrR, FuType.alu, ALUOpType.add),
// C_FSDSP -> List(InstrI, FuType.alu, ALUOpType.add),
C_SWSP -> List(InstrS, FuType.stu, LSUOpType.sw),
// C_FSWSP -> List(InstrI, FuType.alu, ALUOpType.add),
C_SDSP -> List(InstrS, FuType.stu, LSUOpType.sd)
)
val cExtraTable = Array(
C_ADDI4SPN -> List(ImmADD4SPN, REGx2, DtCare, REGrs2p),
......
package xiangshan.backend.decode.isa
import Chisel.BitPat
import chisel3.util._
import xiangshan.{FuType, HasXSParameter}
import xiangshan.backend.decode._
import xiangshan.backend.decode.SrcType.{fp, imm, reg}
import RVF_FPUInstr.{N, Y}
import RVCInstr._
import xiangshan.backend.LSUOpType
object RVDInstr extends HasXSParameter with HasInstrType {
object RVD_LSUInstr extends HasInstrType{
def FLD = BitPat("b?????????????????011?????0000111")
def FSD = BitPat("b?????????????????011?????0100111")
val table = Array(
// FLD -> List(InstrI, FuType.lsu, LSUOpType.ld),
// C_FLD -> List(InstrI, FuType.lsu, LSUOpType.ld),
// C_FLDSP -> List(InstrI, FuType.lsu, LSUOpType.ld),
// FSD -> List(InstrS, FuType.lsu, LSUOpType.sd),
// C_FSD -> List(InstrS, FuType.lsu, LSUOpType.sd),
// C_FSDSP -> List(InstrS, FuType.lsu, LSUOpType.sd)
)
}
object RVD_FPUInstr extends HasXSParameter {
def FADD_D = BitPat("b0000001??????????????????1010011")
def FSUB_D = BitPat("b0000101??????????????????1010011")
def FMUL_D = BitPat("b0001001??????????????????1010011")
......@@ -54,8 +39,14 @@ object RVD_FPUInstr extends HasXSParameter {
def FMSUB_D = BitPat("b?????01??????????????????1000111")
def FNMSUB_D = BitPat("b?????01??????????????????1001011")
def FNMADD_D = BitPat("b?????01??????????????????1001111")
// (isFp, src1Type, src2Type, src3Type, rfWen, fpWen, fuOpType, inputFunc, outputFunc)
val table = Array(
FLD -> List(InstrFI, FuType.ldu, LSUOpType.ld),
FSD -> List(InstrFS, FuType.stu, LSUOpType.sd)
)
// (isFp, src1Type, src2Type, src3Type, rfWen, fpWen, fuOpType, inputFunc, outputFunc)
// val table = Array(
// FLD -> List(Y, reg, imm, imm, N, Y, LSUOpType.ld, in_raw, out_raw),
// C_FLD -> List(Y, reg, imm, imm, N, Y, LSUOpType.ld, in_raw, out_raw),
......@@ -99,10 +90,5 @@ object RVD_FPUInstr extends HasXSParameter {
// FCVT_D_WU -> List(Y, reg, imm, imm, N, Y, wu2f, in_raw, out_raw),
// FCVT_D_L -> List(Y, reg, imm, imm, N, Y, l2f, in_raw, out_raw),
// FCVT_D_LU -> List(Y, reg, imm, imm, N, Y, lu2f, in_raw, out_raw)
)
}
object RVDInstr {
val table = RVD_LSUInstr.table
val extraTable = RVD_FPUInstr.table
// )
}
\ No newline at end of file
package xiangshan.backend.decode.isa
import Chisel.BitPat
import chisel3._
import chisel3.util._
import xiangshan.backend._
import xiangshan.{FuType, HasXSParameter}
import xiangshan.backend.decode._
import xiangshan.backend.decode.SrcType.{fp, imm, reg}
object RVF_LSUInstr extends HasInstrType{
def FLW = BitPat("b?????????????????010?????0000111")
def FSW = BitPat("b?????????????????010?????0100111")
val table = Array(
// FLW -> List(InstrI, FuType.lsu, LSUOpType.flw),
// FSW -> List(InstrS, FuType.lsu, LSUOpType.sw)
)
}
object RVFInstr extends HasXSParameter with HasInstrType {
object RVF_FPUInstr extends HasXSParameter {
def FLW = BitPat("b?????????????????010?????0000111")
def FSW = BitPat("b?????????????????010?????0100111")
def FADD_S = BitPat("b0000000??????????????????1010011")
def FSUB_S = BitPat("b0000100??????????????????1010011")
def FMUL_S = BitPat("b0001000??????????????????1010011")
......@@ -40,19 +33,19 @@ object RVF_FPUInstr extends HasXSParameter {
def FCVT_S_L = BitPat("b110100000010?????????????1010011")
def FCVT_S_LU = BitPat("b110100000011?????????????1010011")
def FMV_W_X = BitPat("b111100000000?????000?????1010011")
def FLW = BitPat("b?????????????????010?????0000111")
def FSW = BitPat("b?????????????????010?????0100111")
def FMADD_S = BitPat("b?????00??????????????????1000011")
def FMSUB_S = BitPat("b?????00??????????????????1000111")
def FNMSUB_S = BitPat("b?????00??????????????????1001011")
def FNMADD_S = BitPat("b?????00??????????????????1001111")
def Y: Bool = true.B
def N: Bool = false.B
val table = Array(
FLW -> List(InstrFI, FuType.ldu, LSUOpType.flw),
FSW -> List(InstrFS, FuType.stu, LSUOpType.sw)
)
// (isFp, src1Type, src2Type, src3Type, rfWen, fpWen, fuOpType, inputFunc, outputFunc)
// val DecodeDefault = List(N, imm, imm, imm, N, N, fadd, in_raw, out_raw)
val table = Array(
// val table = Array(
// FLW -> List(Y, reg, imm, imm, N, Y, LSUOpType.flw, in_raw, out_raw),
// FSW -> List(Y, reg, fp, imm, N, N, LSUOpType.sw, in_raw, out_raw),
// // fp fp -> fp
......@@ -89,11 +82,5 @@ object RVF_FPUInstr extends HasXSParameter {
// FCVT_S_WU -> List(Y, reg, imm, imm, N, Y, wu2f, in_raw, out_box),
// FCVT_S_L -> List(Y, reg, imm, imm, N, Y, l2f, in_raw, out_box),
// FCVT_S_LU -> List(Y, reg, imm, imm, N, Y, lu2f, in_raw, out_box)
)
}
object RVFInstr{
val table = RVF_LSUInstr.table
val extraTable = RVF_FPUInstr.table
// val extraTableDefault = RVF_FPUInstr.DecodeDefault
// )
}
......@@ -73,8 +73,8 @@ object RV32I_BRUInstr extends HasInstrType {
def BGEU = BitPat("b???????_?????_?????_111_?????_1100011")
val table = Array(
JAL -> List(InstrJ, FuType.jmp, BRUOpType.jal),
JALR -> List(InstrI, FuType.jmp, BRUOpType.jalr),
JAL -> List(InstrJ, FuType.jmp, JumpOpType.jal),
JALR -> List(InstrI, FuType.jmp, JumpOpType.jalr),
BEQ -> List(InstrB, FuType.alu, ALUOpType.beq),
BNE -> List(InstrB, FuType.alu, ALUOpType.bne),
......@@ -91,10 +91,10 @@ object RV32I_BRUInstr extends HasInstrType {
ALUOpType.bge -> BTBtype.B,
ALUOpType.bltu -> BTBtype.B,
ALUOpType.bgeu -> BTBtype.B,
// ALUOpType.call -> BTBtype.J,
// ALUOpType.ret -> BTBtype.R,
BRUOpType.jal -> BTBtype.J,
BRUOpType.jalr -> BTBtype.I
JumpOpType.call -> BTBtype.J,
JumpOpType.ret -> BTBtype.R,
JumpOpType.jal -> BTBtype.J,
JumpOpType.jalr -> BTBtype.I
)
}
......
......@@ -3,6 +3,7 @@ package xiangshan.backend.decode.isa
import chisel3._
import chisel3.util._
import xiangshan.FuType
import xiangshan.backend._
import xiangshan.backend.decode.HasInstrType
object RVZicsrInstr extends HasInstrType {
......@@ -13,6 +14,12 @@ object RVZicsrInstr extends HasInstrType {
def CSRRSI = BitPat("b????????????_?????_110_?????_1110011")
def CSRRCI = BitPat("b????????????_?????_111_?????_1110011")
// fixme: add rvzicsr inst
val table = Array()
val table = Array(
CSRRW -> List(InstrI, FuType.csr, CSROpType.wrt),
CSRRS -> List(InstrI, FuType.csr, CSROpType.set),
CSRRC -> List(InstrI, FuType.csr, CSROpType.clr),
CSRRWI -> List(InstrI, FuType.csr, CSROpType.wrti),
CSRRSI -> List(InstrI, FuType.csr, CSROpType.seti),
CSRRCI -> List(InstrI, FuType.csr, CSROpType.clri)
)
}
......@@ -3,12 +3,16 @@ package xiangshan.backend.decode.isa
import chisel3._
import chisel3.util._
import xiangshan.FuType
import xiangshan.backend.ALUOpType
import xiangshan.backend.decode._
import xiangshan.backend.decode.isa.RV64IInstr.InstrI
object RVZifenceiInstr extends HasInstrType {
def FENCEI = BitPat("b000000000000_00000_001_00000_0001111")
// fixme: add rvzifencei inst
val table = Array()
val table = Array(
FENCEI -> List(InstrI, FuType.alu, ALUOpType.add)
)
}
package xiangshan.backend.decode.isa.predecode
import chisel3.util._
import xiangshan.frontend.BrType
object PreDecodeInst {
// def C_JAL = BitPat("b????????????????_?01_?_??_???_??_???_01") // RV32C
def C_J = BitPat("b????????????????_101_?_??_???_??_???_01")
def C_JALR = BitPat("b????????????????_100_?_??_???_00_000_10") //c.jalr & c.jr
def C_BRANCH = BitPat("b????????????????_11?_?_??_???_??_???_01")
def JAL = BitPat("b????????????????_???_?????_1101111")
def JALR = BitPat("b????????????????_000_?????_1100111")
def BRANCH = BitPat("b????????????????_???_?????_1100011")
val brTable = Array(
// C_JAL -> List(BrType.jal),
C_J -> List(BrType.jal),
C_JALR -> List(BrType.jalr),
C_BRANCH -> List(BrType.branch),
JAL -> List(BrType.jal),
JALR -> List(BrType.jalr),
BRANCH -> List(BrType.branch)
)
}
......@@ -3,12 +3,23 @@ package xiangshan.backend.dispatch
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.backend.exu.ExuConfig
import xiangshan.utils._
import utils._
import xiangshan.backend.regfile.RfReadPort
class Dispatch(exuCfg: Array[ExuConfig]) extends XSModule {
case class DispatchParameters
(
DqEnqWidth: Int,
IntDqSize: Int,
FpDqSize: Int,
LsDqSize: Int,
IntDqDeqWidth: Int,
FpDqDeqWidth: Int,
LsDqDeqWidth: Int
)
class Dispatch() extends XSModule {
val io = IO(new Bundle() {
// flush or replay
val redirect = Flipped(ValidIO(new Redirect))
// from rename
val fromRename = Vec(RenameWidth, Flipped(DecoupledIO(new MicroOp)))
......@@ -16,48 +27,90 @@ class Dispatch(exuCfg: Array[ExuConfig]) extends XSModule {
val toRoq = Vec(RenameWidth, DecoupledIO(new MicroOp))
// get RoqIdx
val roqIdxs = Input(Vec(RenameWidth, UInt(RoqIdxWidth.W)))
// enq Moq
val toMoq = Vec(RenameWidth, DecoupledIO(new MicroOp))
// get MoqIdx
val moqIdxs = Input(Vec(RenameWidth, UInt(MoqIdxWidth.W)))
val commits = Input(Vec(CommitWidth, Valid(new RoqCommit)))
// read regfile
val readIntRf = Vec(NRReadPorts, Flipped(new RfReadPort))
val readFpRf = Vec(NRReadPorts, Flipped(new RfReadPort))
val readIntRf = Vec(NRIntReadPorts, Flipped(new RfReadPort))
val readFpRf = Vec(NRFpReadPorts - exuParameters.StuCnt, Flipped(new RfReadPort))
// read reg status (busy/ready)
val intPregRdy = Vec(NRReadPorts, Input(Bool()))
val fpPregRdy = Vec(NRReadPorts, Input(Bool()))
val intPregRdy = Vec(NRIntReadPorts, Input(Bool()))
val fpPregRdy = Vec(NRFpReadPorts - exuParameters.StuCnt, Input(Bool()))
// load + store reg status (busy/ready)
val intMemRegAddr = Vec(NRMemReadPorts, Output(UInt(PhyRegIdxWidth.W)))
val fpMemRegAddr = Vec(exuParameters.StuCnt, Output(UInt(PhyRegIdxWidth.W)))
val intMemRegRdy = Vec(NRMemReadPorts, Input(Bool()))
val fpMemRegRdy = Vec(exuParameters.StuCnt, Input(Bool()))
// to reservation stations
val numExist = Input(Vec(exuParameters.ExuCnt, UInt(log2Ceil(IssQueSize).W)))
val enqIQCtrl = Vec(exuParameters.ExuCnt, DecoupledIO(new MicroOp))
val enqIQData = Vec(exuParameters.ExuCnt, ValidIO(new ExuInput))
val enqIQData = Vec(exuParameters.ExuCnt - exuParameters.LsExuCnt, Output(new ExuInput))
})
// pipeline between rename and dispatch
val dispatch1 = Module(new Dispatch1)
val intDq = Module(new DispatchQueue(dpParams.IntDqSize, dpParams.DqEnqWidth, dpParams.IntDqDeqWidth, DPQType.INT.litValue().toInt))
val fpDq = Module(new DispatchQueue(dpParams.FpDqSize, dpParams.DqEnqWidth, dpParams.FpDqDeqWidth, DPQType.FP.litValue().toInt))
val lsDq = Module(new DispatchQueue(dpParams.LsDqSize, dpParams.DqEnqWidth, dpParams.LsDqDeqWidth, DPQType.LS.litValue().toInt))
// pipeline between rename and dispatch
// accepts all at once
for (i <- 0 until RenameWidth) {
PipelineConnect(io.fromRename(i), dispatch1.io.fromRename(i), dispatch1.io.recv(i), false.B)
}
val intDq = Module(new DispatchQueue(dp1Paremeters.IntDqSize, RenameWidth, IntDqDeqWidth, "IntDpQ"))
val fpDq = Module(new DispatchQueue(dp1Paremeters.FpDqSize, RenameWidth, FpDqDeqWidth, "FpDpQ"))
val lsDq = Module(new DispatchQueue(dp1Paremeters.LsDqSize, RenameWidth, LsDqDeqWidth, "LsDpQ"))
val dispatch2 = Module(new Dispatch2(exuCfg))
// dispatch 1: accept uops from rename and dispatch them to the three dispatch queues
dispatch1.io.redirect <> io.redirect
dispatch1.io.toRoq <> io.toRoq
dispatch1.io.roqIdxs <> io.roqIdxs
dispatch1.io.toMoq <> io.toMoq
dispatch1.io.moqIdxs <> io.moqIdxs
dispatch1.io.toIntDq <> intDq.io.enq
dispatch1.io.toFpDq <> fpDq.io.enq
dispatch1.io.toLsDq <> lsDq.io.enq
// dispatch queue cancels the uops
// dispatch queue: queue uops and dispatch them to different reservation stations or issue queues
// it may cancel the uops
intDq.io.redirect <> io.redirect
intDq.io.commits <> io.commits
fpDq.io.redirect <> io.redirect
fpDq.io.commits <> io.commits
lsDq.io.redirect <> io.redirect
lsDq.io.commits <> io.commits
// Int dispatch queue to Int reservation stations
val intDispatch = Module(new Dispatch2Int)
intDispatch.io.fromDq <> intDq.io.deq
intDispatch.io.readRf <> io.readIntRf
intDispatch.io.regRdy := io.intPregRdy
intDispatch.io.numExist.zipWithIndex.map({case (num, i) => num := io.numExist(i)})
intDispatch.io.enqIQCtrl.zipWithIndex.map({case (enq, i) => enq <> io.enqIQCtrl(i)})
intDispatch.io.enqIQData.zipWithIndex.map({case (enq, i) => enq <> io.enqIQData(i)})
// TODO: Fp dispatch queue to Fp reservation stations
if (exuParameters.FpExuCnt > 0) {
val fpDispatch = Module(new Dispatch2Fp)
fpDispatch.io.fromDq <> fpDq.io.deq
fpDispatch.io.readRf <> io.readFpRf
fpDispatch.io.regRdy <> io.fpPregRdy
fpDispatch.io.numExist.zipWithIndex.map({case (num, i) => num := io.numExist(i + exuParameters.IntExuCnt)})
fpDispatch.io.enqIQCtrl.zipWithIndex.map({case (enq, i) => enq <> io.enqIQCtrl(i + exuParameters.IntExuCnt)})
fpDispatch.io.enqIQData.zipWithIndex.map({case (enq, i) => enq <> io.enqIQData(i + exuParameters.IntExuCnt)})
}
else {
fpDq.io.deq <> DontCare
io.readFpRf <> DontCare
}
// dispatch2 only receives valid uops from dispatch queue
dispatch2.io.fromIntDq <> intDq.io.deq
dispatch2.io.fromFpDq <> fpDq.io.deq
dispatch2.io.fromLsDq <> lsDq.io.deq
dispatch2.io.readIntRf <> io.readIntRf
dispatch2.io.readFpRf <> io.readFpRf
dispatch2.io.intPregRdy <> io.intPregRdy
dispatch2.io.fpPregRdy <> io.fpPregRdy
dispatch2.io.enqIQCtrl <> io.enqIQCtrl
dispatch2.io.enqIQData <> io.enqIQData
dispatch2.io.numExist <> io.numExist
// Load/store dispatch queue to load/store issue queues
val lsDispatch = Module(new Dispatch2Ls)
lsDispatch.io.fromDq <> lsDq.io.deq
lsDispatch.io.intRegAddr <> io.intMemRegAddr
lsDispatch.io.fpRegAddr <> io.fpMemRegAddr
lsDispatch.io.intRegRdy <> io.intMemRegRdy
lsDispatch.io.fpRegRdy <> io.fpMemRegRdy
lsDispatch.io.numExist.zipWithIndex.map({case (num, i) => num := io.numExist(exuParameters.IntExuCnt + exuParameters.FpExuCnt + i)})
lsDispatch.io.enqIQCtrl.zipWithIndex.map({case (enq, i) => enq <> io.enqIQCtrl(exuParameters.IntExuCnt + exuParameters.FpExuCnt + i)})
}
......@@ -3,17 +3,10 @@ package xiangshan.backend.dispatch
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils.{XSDebug, XSInfo, XSWarn}
case class DP1Parameters
(
IntDqSize: Int,
FpDqSize: Int,
LsDqSize: Int
)
import utils.{XSDebug, XSError, XSInfo}
// read rob and enqueue
class Dispatch1 extends XSModule{
class Dispatch1 extends XSModule {
val io = IO(new Bundle() {
val redirect = Flipped(ValidIO(new Redirect))
// from rename
......@@ -23,83 +16,142 @@ class Dispatch1 extends XSModule{
val toRoq = Vec(RenameWidth, DecoupledIO(new MicroOp))
// get RoqIdx
val roqIdxs = Input(Vec(RenameWidth, UInt(RoqIdxWidth.W)))
// enq Moq
val toMoq = Vec(RenameWidth, DecoupledIO(new MicroOp))
// get MoqIdx
val moqIdxs = Input(Vec(RenameWidth, UInt(MoqIdxWidth.W)))
// to dispatch queue
val toIntDq = Vec(RenameWidth, DecoupledIO(new MicroOp))
val toFpDq = Vec(RenameWidth, DecoupledIO(new MicroOp))
val toLsDq = Vec(RenameWidth, DecoupledIO(new MicroOp))
val toIntDq = Vec(dpParams.DqEnqWidth, DecoupledIO(new MicroOp))
val toFpDq = Vec(dpParams.DqEnqWidth, DecoupledIO(new MicroOp))
val toLsDq = Vec(dpParams.DqEnqWidth, DecoupledIO(new MicroOp))
})
// check whether valid uops are canceled
val cancelled = Wire(Vec(RenameWidth, Bool()))
for (i <- 0 until RenameWidth) {
cancelled(i) := io.fromRename(i).bits.brTag.needFlush(io.redirect)
XSDebug(io.redirect.valid, p"pc=${Hexadecimal(io.fromRename(i).bits.cf.pc)} brTag:${io.redirect.bits.brTag}\n")
}
/**
* Part 1: choose the target dispatch queue and the corresponding write ports
*/
// valid bits for different dispatch queues
val isInt = WireInit(VecInit(io.fromRename.map(uop => FuType.isIntExu(uop.bits.ctrl.fuType))))
val isFp = WireInit(VecInit(io.fromRename.map(uop => FuType.isFpExu (uop.bits.ctrl.fuType))))
val isLs = WireInit(VecInit(io.fromRename.map(uop => FuType.isMemExu(uop.bits.ctrl.fuType))))
// enqueue handshake
val enq_ready = Wire(Vec(RenameWidth, Bool()))
val enq_valid = Wire(Vec(RenameWidth, Bool()))
// 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) {
enq_ready(i) := (io.toIntDq(i).ready && FuType.isIntExu(io.fromRename(i).bits.ctrl.fuType)) ||
(io.toFpDq(i).ready && FuType.isFpExu(io.fromRename(i).bits.ctrl.fuType )) ||
(io.toLsDq(i).ready && FuType.isMemExu(io.fromRename(i).bits.ctrl.fuType))
enq_valid(i) := io.toIntDq(i).valid || io.toFpDq(i).valid || io.toLsDq(i).valid
io.recv(i) := (enq_ready(i) && enq_valid(i)) || cancelled(i)
XSInfo(io.recv(i) && !cancelled(i), "pc 0x%x accepted by queue %x %x %x\n",
io.fromRename(i).bits.cf.pc, io.toIntDq(i).valid, io.toFpDq(i).valid, io.toLsDq(i).valid)
XSInfo(io.recv(i) && cancelled(i), "pc 0x%x with brTag %x cancelled\n",
io.fromRename(i).bits.cf.pc, io.redirect.bits.brTag.value)
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
// latch indexes from roq in case of DQ not fire
/**
* Part 2: acquire ROQ (all) and LSROQ (load/store only) indexes
*/
val cancelled = WireInit(VecInit(Seq.fill(RenameWidth)(io.redirect.valid && !io.redirect.bits.isReplay)))
val uopWithIndex = Wire(Vec(RenameWidth, new MicroOp))
val roqIndexReg = Reg(Vec(RenameWidth, UInt(RoqIdxWidth.W)))
val roqIndexRegValid = RegInit(VecInit(Seq.fill(RenameWidth)(false.B)))
val roqIndexAcquired = WireInit(VecInit(Seq.tabulate(RenameWidth)(i => io.toRoq(i).ready || roqIndexRegValid(i))))
val lsroqIndexReg = Reg(Vec(RenameWidth, UInt(MoqIdxWidth.W)))
val lsroqIndexRegValid = RegInit(VecInit(Seq.fill(RenameWidth)(false.B)))
val lsroqIndexAcquired = WireInit(VecInit(Seq.tabulate(RenameWidth)(i => io.toMoq(i).ready || lsroqIndexRegValid(i))))
for (i <- 0 until RenameWidth) {
// dispatch queue does not accept the MicroOp
// however, ROQ has fired
when (io.toRoq(i).fire() && !io.recv(i)) {
// input for ROQ and LSROQ
io.toRoq(i).valid := io.fromRename(i).valid && !roqIndexRegValid(i)
io.toRoq(i).bits := io.fromRename(i).bits
io.toRoq(i).bits.ctrl.dpqType := Cat(isLs(i), isFp(i))
io.toRoq(i).bits.moqIdx := Mux(lsroqIndexRegValid(i), lsroqIndexReg(i), io.moqIdxs(i))
io.toMoq(i).valid := io.fromRename(i).valid && !lsroqIndexRegValid(i) && isLs(i) && roqIndexAcquired(i) && !cancelled(i)
io.toMoq(i).bits := io.fromRename(i).bits
io.toMoq(i).bits.roqIdx := Mux(roqIndexRegValid(i), roqIndexReg(i), io.roqIdxs(i))
// receive indexes from ROQ and LSROQ
when(io.toRoq(i).fire() && !io.recv(i)) {
roqIndexReg(i) := io.roqIdxs(i)
roqIndexRegValid(i) := true.B
}
.elsewhen (io.recv(i)) {
}.elsewhen(io.recv(i)) {
roqIndexRegValid(i) := false.B
}
XSDebug(io.toRoq(i).fire() && !io.recv(i),
"pc 0x%x receives nboq %x but not accepted by queue (and it waits)\n",
io.fromRename(i).bits.cf.pc, io.roqIdxs(i))
when(io.toMoq(i).fire() && !io.recv(i)) {
lsroqIndexReg(i) := io.moqIdxs(i)
lsroqIndexRegValid(i) := true.B
}.elsewhen(io.recv(i)) {
lsroqIndexRegValid(i) := false.B
}
// append ROQ and LSROQ indexed to uop
uopWithIndex(i) := io.fromRename(i).bits
uopWithIndex(i).roqIdx := Mux(roqIndexRegValid(i), roqIndexReg(i), io.roqIdxs(i))
uopWithIndex(i).moqIdx := Mux(lsroqIndexRegValid(i), lsroqIndexReg(i), io.moqIdxs(i))
XSDebug(io.toRoq(i).fire(), p"pc 0x${Hexadecimal(io.fromRename(i).bits.cf.pc)} receives nroq ${io.roqIdxs(i)}\n")
XSDebug(io.toMoq(i).fire(), p"pc 0x${Hexadecimal(io.fromRename(i).bits.cf.pc)} receives mroq ${io.moqIdxs(i)}\n")
if (i > 0) {
XSError(io.toRoq(i).fire() && !io.toRoq(i - 1).ready && io.toRoq(i - 1).valid, p"roq handshake not continuous $i")
}
}
// append nroq to uop
val uop_nroq = Wire(Vec(RenameWidth, new MicroOp))
/**
* Part 3: send uop (should not be cancelled) with correct indexes to dispatch queues
*/
val orderedEnqueue = Wire(Vec(RenameWidth, Bool()))
val canEnqueue = Wire(Vec(RenameWidth, Bool()))
var prevCanEnqueue = true.B
for (i <- 0 until RenameWidth) {
uop_nroq(i) := io.fromRename(i).bits
uop_nroq(i).roqIdx := Mux(roqIndexRegValid(i), roqIndexReg(i), io.roqIdxs(i))
orderedEnqueue(i) := prevCanEnqueue
canEnqueue(i) := !cancelled(i) && roqIndexAcquired(i) && (!isLs(i) || lsroqIndexAcquired(i))
val enqReady = (io.toIntDq(intIndex.io.reverseMapping(i).bits).ready && intIndex.io.reverseMapping(i).valid) ||
(io.toFpDq(fpIndex.io.reverseMapping(i).bits).ready && fpIndex.io.reverseMapping(i).valid) ||
(io.toLsDq(lsIndex.io.reverseMapping(i).bits).ready && lsIndex.io.reverseMapping(i).valid)
prevCanEnqueue = prevCanEnqueue && (!io.fromRename(i).valid || (canEnqueue(i) && enqReady))
}
for (i <- 0 until dpParams.DqEnqWidth) {
io.toIntDq(i).bits := uopWithIndex(intIndex.io.mapping(i).bits)
io.toIntDq(i).valid := intIndex.io.mapping(i).valid &&
canEnqueue(intIndex.io.mapping(i).bits) &&
orderedEnqueue(intIndex.io.mapping(i).bits)
// uop can enqueue when rename.valid and roq.valid
val can_enqueue = Wire(Vec(RenameWidth, Bool()))
for (i <- 0 until RenameWidth) {
can_enqueue(i) := io.fromRename(i).valid && (io.toRoq(i).ready || roqIndexRegValid(i)) && !cancelled(i)
io.toIntDq(i).valid := can_enqueue(i) && FuType.isIntExu(io.fromRename(i).bits.ctrl.fuType)
io.toIntDq(i).bits := uop_nroq(i)
io.toFpDq(i).valid := can_enqueue(i) && FuType.isFpExu(io.fromRename(i).bits.ctrl.fuType)
io.toFpDq(i).bits := uop_nroq(i)
io.toLsDq(i).valid := can_enqueue(i) && FuType.isMemExu(io.fromRename(i).bits.ctrl.fuType)
io.toLsDq(i).bits := uop_nroq(i)
io.toFpDq(i).bits := uopWithIndex(fpIndex.io.mapping(i).bits)
io.toFpDq(i).valid := fpIndex.io.mapping(i).valid &&
canEnqueue(fpIndex.io.mapping(i).bits) &&
orderedEnqueue(fpIndex.io.mapping(i).bits)
io.toLsDq(i).bits := uopWithIndex(lsIndex.io.mapping(i).bits)
io.toLsDq(i).valid := lsIndex.io.mapping(i).valid &&
canEnqueue(lsIndex.io.mapping(i).bits) &&
orderedEnqueue(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")
}
// ack roq and input (rename) when both roq and dispatch queue are ready
val recv_vector =(0 until RenameWidth).map(i => !io.fromRename(i).valid || io.recv(i))
val all_recv = recv_vector.reduce((x, y) => x && y).asBool()
/**
* 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))
for (i <- 0 until RenameWidth) {
io.toRoq(i).bits <> io.fromRename(i).bits
io.toRoq(i).valid := io.fromRename(i).valid && !roqIndexRegValid(i)// && !cancelled(i)
XSDebug(io.toRoq(i).fire(), "pc 0x%x receives nroq %d\n", io.fromRename(i).bits.cf.pc, io.roqIdxs(i))
if (i > 0) {
XSWarn(io.toRoq(i).fire() && !io.toRoq(i - 1).ready && io.toRoq(i - 1).valid,
"roq handshake not continuous %d", i.U)
}
io.fromRename(i).ready := all_recv
XSDebug("v:%d r:%d pc 0x%x of type %b is in %d-th slot\n",
val enqFire = (io.toIntDq(intIndex.io.reverseMapping(i).bits).fire() && intIndex.io.reverseMapping(i).valid) ||
(io.toFpDq(fpIndex.io.reverseMapping(i).bits).fire() && fpIndex.io.reverseMapping(i).valid) ||
(io.toLsDq(lsIndex.io.reverseMapping(i).bits).fire() && lsIndex.io.reverseMapping(i).valid)
io.recv(i) := enqFire || cancelled(i)
io.fromRename(i).ready := Cat(readyVector).andR()
XSInfo(io.recv(i) && !cancelled(i),
p"pc 0x${Hexadecimal(io.fromRename(i).bits.cf.pc)} type(${isInt(i)}, ${isFp(i)}, ${isLs(i)}) " +
p"roq ${uopWithIndex(i).roqIdx} lsroq ${uopWithIndex(i).moqIdx} is accepted by dispatch queue " +
p"(${intIndex.io.reverseMapping(i).bits}, ${fpIndex.io.reverseMapping(i).bits}, ${lsIndex.io.reverseMapping(i).bits})\n")
XSInfo(io.recv(i) && cancelled(i),
p"pc 0x${Hexadecimal(io.fromRename(i).bits.cf.pc)} with brTag ${io.fromRename(i).bits.brTag.value} cancelled\n")
XSDebug(io.fromRename(i).valid, "v:%d r:%d pc 0x%x of type %b is in %d-th slot\n",
io.fromRename(i).valid, io.fromRename(i).ready, io.fromRename(i).bits.cf.pc, io.fromRename(i).bits.ctrl.fuType, i.U)
}
val renameFireCnt = PopCount(io.recv)
val enqFireCnt = PopCount(io.toIntDq.map(_.fire)) + PopCount(io.toFpDq.map(_.fire)) + PopCount(io.toLsDq.map(_.fire))
XSError(enqFireCnt > renameFireCnt, "enqFireCnt should not be greater than renameFireCnt\n")
}
package xiangshan.backend.dispatch
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.backend.exu.ExuConfig
import xiangshan.backend.regfile.RfReadPort
import xiangshan.utils.{XSDebug, XSInfo}
class Dispatch2(exuCfg: Array[ExuConfig]) extends XSModule{
val io = IO(new Bundle() {
// from dispatch queues
val fromIntDq = Flipped(Vec(IntDqDeqWidth, DecoupledIO(new MicroOp)))
val fromFpDq = Flipped(Vec(FpDqDeqWidth, DecoupledIO(new MicroOp)))
val fromLsDq = Flipped(Vec(LsDqDeqWidth, DecoupledIO(new MicroOp)))
// read regfile
val readIntRf = Vec(NRReadPorts, Flipped(new RfReadPort))
val readFpRf = Vec(NRReadPorts, Flipped(new RfReadPort))
// read reg status (busy/ready)
val intPregRdy = Vec(NRReadPorts, Input(Bool()))
val fpPregRdy = Vec(NRReadPorts, Input(Bool()))
// enq Issue Queue
val numExist = Input(Vec(exuCfg.length, UInt(log2Ceil(IssQueSize).W)))
val enqIQCtrl = Vec(exuCfg.length, DecoupledIO(new MicroOp))
val enqIQData = Vec(exuCfg.length, ValidIO(new ExuInput))
})
for (i <- 0 until IntDqDeqWidth) {
XSDebug(io.fromIntDq(i).valid,
p"int dp queue $i: ${Hexadecimal(io.fromIntDq(i).bits.cf.pc)} type ${Binary(io.fromIntDq(i).bits.ctrl.fuType)}\n")
}
for (i <- 0 until FpDqDeqWidth) {
XSDebug(io.fromFpDq(i).valid,
p"fp dp queue $i: ${Hexadecimal(io.fromFpDq(i).bits.cf.pc)} type ${Binary(io.fromFpDq(i).bits.ctrl.fuType)}\n")
}
for (i <- 0 until LsDqDeqWidth) {
XSDebug(io.fromLsDq(i).valid,
p"ls dp queue $i: ${Hexadecimal(io.fromLsDq(i).bits.cf.pc)} type ${Binary(io.fromLsDq(i).bits.ctrl.fuType)}\n")
}
// inst indexes for reservation stations
val rsIndexGen = Module(new DispatchGen(exuCfg))
rsIndexGen.io.fromIntDq := io.fromIntDq
rsIndexGen.io.fromFpDq := io.fromFpDq
rsIndexGen.io.fromLsDq := io.fromLsDq
rsIndexGen.io.numExist := io.numExist
val instValid = rsIndexGen.io.enqIQIndex.map(_.valid)
val allIndex = rsIndexGen.io.enqIQIndex.map(_.bits)
allIndex.zipWithIndex.map({case(index, i) => XSDebug(instValid(i), p"dispatch to iq index $i: $index\n")})
// regfile read ports
io.readIntRf <> DontCare
val regfileRPGen = Module(new RegfileReadPortGen())
(0 until exuParameters.IntExuCnt).map(i => regfileRPGen.io.intIQEnqIndex(i) := rsIndexGen.io.enqIQIndex(i))
(0 until exuParameters.FpExuCnt).map(i => regfileRPGen.io.fpIQEnqIndex(i) := rsIndexGen.io.enqIQIndex(exuParameters.IntExuCnt + i))
(0 until exuParameters.LsExuCnt).map(i => regfileRPGen.io.lsIQEnqIndex(i) := rsIndexGen.io.enqIQIndex(exuParameters.IntExuCnt + exuParameters.FpExuCnt + i))
for (i <- 0 until 2 * exuParameters.IntExuCnt) {
val bits = io.fromIntDq(regfileRPGen.io.readIntRf(i)).bits
io.readIntRf(i).addr := (if (i % 2 == 0) bits.psrc1 else bits.psrc2)
XSDebug(p"regfile $i from ${regfileRPGen.io.readIntRf(i)}\n")
}
for (i <- 0 until 3*exuParameters.FpExuCnt) {
val bits = io.fromFpDq(regfileRPGen.io.readFpRf(i)).bits
io.readFpRf(i).addr := (if (i % 3 == 0) bits.psrc1 else if (i % 3 == 1) bits.psrc2 else bits.psrc3)
}
for (i <- 0 until exuParameters.LduCnt) {
val start = 2 * exuParameters.AluCnt
io.readIntRf(start+i).addr := io.fromLsDq(regfileRPGen.io.readIntRf(start+i))
}
for (i <- 0 until 2*exuParameters.StuCnt) {
val start = 2 * exuParameters.AluCnt + exuParameters.LduCnt
val bits = io.fromLsDq(regfileRPGen.io.readIntRf(start + i)).bits
io.readIntRf(start + i).addr := (if (i % 2 == 0) bits.psrc1 else bits.psrc2)
}
for (i <- 0 until NRReadPorts) {
XSDebug(p"regfile $i: addr ${io.readIntRf(i).addr}, state ${io.intPregRdy(i)}\n")
}
// TODO uncomment me when fmac > 0
io.readFpRf <> DontCare
// insert into reservation station
val instIdxes = (0 until exuParameters.ExuCnt).map(i => Cat(!instValid(i), allIndex(i)))
io.enqIQCtrl.zipWithIndex map { case (enq, i) =>
if (i < exuParameters.IntExuCnt) {
enq.valid := !instIdxes(i)(2) && io.fromIntDq(instIdxes(i)(1, 0)).valid
enq.bits := io.fromIntDq(instIdxes(i)(1, 0)).bits
val startIndex = regfileRPGen.io.intIQRfSrc(i)
enq.bits.src1State := io.intPregRdy(startIndex)
enq.bits.src2State := io.intPregRdy(startIndex + 1.U)
}
else if (i < exuParameters.IntExuCnt + exuParameters.FpExuCnt) {
val startIndex = regfileRPGen.io.fpIQRfSrc(i - exuParameters.IntExuCnt)
enq.valid := !instIdxes(i)(2) && io.fromFpDq(instIdxes(i)(1, 0)).valid
enq.bits := io.fromFpDq(instIdxes(i)(1, 0)).bits
enq.bits.src1State := io.fpPregRdy(startIndex)
enq.bits.src2State := io.fpPregRdy(startIndex + 1.U)
enq.bits.src3State := io.fpPregRdy(startIndex + 2.U)
}
else {
// TODO: load store with fp
val startIndex = regfileRPGen.io.lsIQRfSrc(i - exuParameters.IntExuCnt - exuParameters.FpExuCnt)
enq.valid := !instIdxes(i)(2) && io.fromLsDq(instIdxes(i)(1, 0)).valid
enq.bits := io.fromLsDq(instIdxes(i)(1, 0)).bits
if (i < exuParameters.IntExuCnt + exuParameters.FpExuCnt + exuParameters.LduCnt) {
enq.bits.src1State := io.intPregRdy(startIndex)
}
else {
enq.bits.src1State := io.intPregRdy(startIndex)
enq.bits.src2State := io.intPregRdy(startIndex + 1.U)
}
}
XSInfo(enq.fire(), "pc 0x%x with type %b srcState(%d %d %d) enters reservation station %d from %d\n",
enq.bits.cf.pc, enq.bits.ctrl.fuType, enq.bits.src1State, enq.bits.src2State, enq.bits.src3State, i.U, instIdxes(i))
}
// responds to dispatch queue
for (i <- 0 until IntDqDeqWidth) {
io.fromIntDq(i).ready := (io.enqIQCtrl.zipWithIndex map {case (rs, j) =>
(rs.ready && instIdxes(j) === i.U && (j < exuParameters.IntExuCnt).asBool())
}).reduce((l, r) => l || r)
XSInfo(io.fromIntDq(i).fire(), "pc 0x%x leaves Int dispatch queue with nroq %d\n",
io.fromIntDq(i).bits.cf.pc, io.fromIntDq(i).bits.roqIdx)
XSDebug(io.fromIntDq(i).valid && !io.fromIntDq(i).ready,
"pc 0x%x waits at Int dispatch queue with index %d\n",
io.fromIntDq(i).bits.cf.pc, i.U)
}
for (i <- 0 until FpDqDeqWidth) {
io.fromFpDq(i).ready := (io.enqIQCtrl.zipWithIndex map {case (rs, j) =>
(rs.ready && instIdxes(j) === i.U
&& (j >= exuParameters.IntExuCnt && j < exuParameters.IntExuCnt + exuParameters.FpExuCnt).asBool())
}).reduce((l, r) => l || r)
XSInfo(io.fromFpDq(i).fire(), "pc 0x%x leaves Fp dispatch queue with nroq %d\n",
io.fromFpDq(i).bits.cf.pc, io.fromFpDq(i).bits.roqIdx)
XSDebug(io.fromFpDq(i).valid && !io.fromFpDq(i).ready,
"pc 0x%x waits at Fp dispatch queue with index %d\n",
io.fromFpDq(i).bits.cf.pc, i.U)
}
for (i <- 0 until LsDqDeqWidth) {
io.fromLsDq(i).ready := (io.enqIQCtrl.zipWithIndex map {case (rs, j) =>
(rs.ready && instIdxes(j) === i.U
&& (j >= exuParameters.IntExuCnt + exuParameters.FpExuCnt).asBool())
}).reduce((l, r) => l || r)
XSInfo(io.fromLsDq(i).fire(), "pc 0x%x leaves Ls dispatch queue with nroq %d\n",
io.fromLsDq(i).bits.cf.pc, io.fromLsDq(i).bits.roqIdx)
XSDebug(io.fromLsDq(i).valid && !io.fromLsDq(i).ready,
"pc 0x%x waits at Ls dispatch queue with index %d\n",
io.fromLsDq(i).bits.cf.pc, i.U)
}
// TODO: store needs data from FpRegfile
val intExuIndexReg = Reg(Vec(exuParameters.IntExuCnt, UInt(log2Ceil(NRReadPorts).W)))
val fpExuIndexReg = Reg(Vec(exuParameters.FpExuCnt, UInt(log2Ceil(NRReadPorts).W)))
val lsExuIndexReg = Reg(Vec(exuParameters.LduCnt + exuParameters.StuCnt, UInt(log2Ceil(NRReadPorts).W)))
(0 until exuParameters.IntExuCnt).map(i => intExuIndexReg(i) := regfileRPGen.io.intIQRfSrc(i))
(0 until exuParameters.FpExuCnt).map(i => fpExuIndexReg(i) := regfileRPGen.io.fpIQRfSrc(i))
(0 until exuParameters.LsExuCnt).map(i => lsExuIndexReg(i) := regfileRPGen.io.lsIQRfSrc(i))
// TODO: remove uop when reservation stations deal with imme
val uop_reg = Reg(Vec(exuParameters.ExuCnt, new MicroOp))
val data_valid = Reg(Vec(exuParameters.ExuCnt, Bool()))
for (i <- 0 until exuParameters.ExuCnt) {
data_valid(i) := io.enqIQCtrl(i).fire()
uop_reg(i) := io.enqIQCtrl(i).bits
io.enqIQData(i).valid := DontCare
io.enqIQData(i).bits := DontCare
val srcIndex = Wire(Vec(3, UInt(4.W)))
if (i < exuParameters.IntExuCnt) {
val startIndex = intExuIndexReg(i)
io.enqIQData(i).bits.src1 := Mux(uop_reg(i).ctrl.src1Type === SrcType.pc,
uop_reg(i).cf.pc, io.readIntRf(startIndex).data)
io.enqIQData(i).bits.src2 := Mux(uop_reg(i).ctrl.src2Type === SrcType.imm,
uop_reg(i).ctrl.imm, io.readIntRf(startIndex + 1.U).data)
srcIndex(0) := startIndex
srcIndex(1) := startIndex + 1.U
srcIndex(2) := 0.U
}
else if (i < exuParameters.IntExuCnt + exuParameters.FpExuCnt) {
val startIndex = fpExuIndexReg(i - exuParameters.IntExuCnt)
io.enqIQData(i).bits.src1 := io.readFpRf(startIndex).data
io.enqIQData(i).bits.src2 := io.readFpRf(startIndex + 1.U).data
io.enqIQData(i).bits.src3 := io.readFpRf(startIndex + 2.U).data
srcIndex(0) := startIndex
srcIndex(1) := startIndex + 1.U
srcIndex(2) := startIndex + 2.U
}
else {
val startIndex = lsExuIndexReg(i - exuParameters.IntExuCnt - exuParameters.FpExuCnt)
io.enqIQData(i).bits.src1 := Mux(uop_reg(i).ctrl.src1Type === SrcType.pc,
uop_reg(i).cf.pc, io.readIntRf(startIndex).data)
io.enqIQData(i).bits.src2 := Mux(uop_reg(i).ctrl.src2Type === SrcType.imm,
uop_reg(i).ctrl.imm, io.readIntRf(startIndex + 1.U).data)
srcIndex(0) := startIndex
srcIndex(1) := startIndex + 1.U
srcIndex(2) := 0.U
}
XSDebug(data_valid(i),
"pc 0x%x reads operands from (%d, %d, %x), (%d, %d, %x), (%d, %d, %x)\n",
uop_reg(i).cf.pc,
srcIndex(0), uop_reg(i).psrc1, io.enqIQData(i).bits.src1,
srcIndex(1), uop_reg(i).psrc2, io.enqIQData(i).bits.src2,
srcIndex(2), uop_reg(i).psrc3, io.enqIQData(i).bits.src3)
}
}
package xiangshan.backend.dispatch
import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import xiangshan.backend.regfile.RfReadPort
import xiangshan.backend.exu._
class Dispatch2Fp extends XSModule {
val io = IO(new Bundle() {
val fromDq = Flipped(Vec(dpParams.FpDqDeqWidth, DecoupledIO(new MicroOp)))
val readRf = Vec(NRFpReadPorts - exuParameters.StuCnt, Flipped(new RfReadPort))
val regRdy = Vec(NRFpReadPorts - exuParameters.StuCnt, Input(Bool()))
val numExist = Input(Vec(exuParameters.FpExuCnt, UInt(log2Ceil(IssQueSize).W)))
val enqIQCtrl = Vec(exuParameters.FpExuCnt, DecoupledIO(new MicroOp))
val enqIQData = Vec(exuParameters.FpExuCnt, Output(new ExuInput))
})
/**
* Part 1: generate indexes for reservation stations
*/
assert(exuParameters.JmpCnt == 1)
val fmacIndexGen = Module(new IndexMapping(dpParams.FpDqDeqWidth, exuParameters.FmacCnt, true))
val fmiscIndexGen = Module(new IndexMapping(dpParams.FpDqDeqWidth, exuParameters.FmiscCnt, true))
val fmacPriority = PriorityGen((0 until exuParameters.FmacCnt).map(i => io.numExist(i)))
val fmiscPriority = PriorityGen((0 until exuParameters.FmiscCnt).map(i => io.numExist(i+exuParameters.FmacCnt)))
for (i <- 0 until dpParams.FpDqDeqWidth) {
fmacIndexGen.io.validBits(i) := io.fromDq(i).valid && Exu.fmacExeUnitCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
fmiscIndexGen.io.validBits(i) := io.fromDq(i).valid && Exu.fmiscExeUnitCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
XSDebug(io.fromDq(i).valid,
p"fp dp queue $i: ${Hexadecimal(io.fromDq(i).bits.cf.pc)} type ${Binary(io.fromDq(i).bits.ctrl.fuType)}\n")
}
for (i <- 0 until exuParameters.FmacCnt) {
fmacIndexGen.io.priority(i) := fmacPriority(i)
}
for (i <- 0 until exuParameters.FmiscCnt) {
fmiscIndexGen.io.priority(i) := fmiscPriority(i)
}
val allIndexGen = Seq(fmacIndexGen, fmiscIndexGen)
val validVec = allIndexGen.map(_.io.mapping.map(_.valid)).reduceLeft(_ ++ _)
val indexVec = allIndexGen.map(_.io.mapping.map(_.bits)).reduceLeft(_ ++ _)
val rsValidVec = (0 until dpParams.FpDqDeqWidth).map(i => Cat(allIndexGen.map(_.io.reverseMapping(i).valid)).orR())
val rsIndexVec = (0 until dpParams.FpDqDeqWidth).map({i =>
val indexOffset = Seq(0, exuParameters.FmacCnt)
allIndexGen.zipWithIndex.map{
case (index, j) => Mux(index.io.reverseMapping(i).valid, index.io.reverseMapping(i).bits + indexOffset(j).U, 0.U)
}.reduce(_ | _)
})
for (i <- validVec.indices) {
// XSDebug(p"mapping $i: valid ${validVec(i)} index ${indexVec(i)}\n")
}
for (i <- rsValidVec.indices) {
// XSDebug(p"fmac reverse $i: valid ${fmacIndexGen.io.reverseMapping(i).valid} index ${fmacIndexGen.io.reverseMapping(i).bits}\n")
// XSDebug(p"fmisc reverse $i: valid ${fmiscIndexGen.io.reverseMapping(i).valid} index ${fmiscIndexGen.io.reverseMapping(i).bits}\n")
// XSDebug(p"reverseMapping $i: valid ${rsValidVec(i)} index ${rsIndexVec(i)}\n")
}
/**
* Part 2: assign regfile read ports
*/
val fpStaticIndex = Seq(0, 1, 2, 3)
val fpDynamicIndex = Seq(4, 5)
val fpStaticMappedValid = fpStaticIndex.map(i => validVec(i))
val fpDynamicMappedValid = fpDynamicIndex.map(i => validVec(i))
val (fpReadPortSrc, fpDynamicExuSrc) = RegfileReadPortGen(fpStaticMappedValid, fpDynamicMappedValid)
val fpStaticMapped = fpStaticIndex.map(i => indexVec(i))
val fpDynamicMapped = fpDynamicIndex.map(i => indexVec(i))
for (i <- fpStaticIndex.indices) {
val index = WireInit(VecInit(fpStaticMapped(i) +: fpDynamicMapped))
io.readRf(3*i ).addr := io.fromDq(index(fpReadPortSrc(i))).bits.psrc1
io.readRf(3*i+1).addr := io.fromDq(index(fpReadPortSrc(i))).bits.psrc2
io.readRf(3*i+2).addr := io.fromDq(index(fpReadPortSrc(i))).bits.psrc3
}
val readPortIndex = Wire(Vec(exuParameters.FpExuCnt, UInt(log2Ceil(NRFpReadPorts - exuParameters.StuCnt).W)))
fpStaticIndex.zipWithIndex.map({case (index, i) => readPortIndex(index) := (3*i).U})
fpDynamicIndex.zipWithIndex.map({case (index, i) => readPortIndex(index) := 3.U * fpDynamicExuSrc(i)})
/**
* Part 3: dispatch to reservation stations
*/
for (i <- 0 until exuParameters.FpExuCnt) {
val enq = io.enqIQCtrl(i)
enq.valid := validVec(i)
enq.bits := io.fromDq(indexVec(i)).bits
enq.bits.src1State := io.regRdy(readPortIndex(i))
enq.bits.src2State := io.regRdy(readPortIndex(i) + 1.U)
enq.bits.src3State := io.regRdy(readPortIndex(i) + 2.U)
XSInfo(enq.fire(), p"pc 0x${Hexadecimal(enq.bits.cf.pc)} with type ${enq.bits.ctrl.fuType} " +
p"srcState(${enq.bits.src1State} ${enq.bits.src2State} ${enq.bits.src3State}) " +
p"enters reservation station $i from ${indexVec(i)}\n")
}
/**
* Part 4: response to dispatch queue
*/
for (i <- 0 until dpParams.FpDqDeqWidth) {
io.fromDq(i).ready := rsValidVec(i) && io.enqIQCtrl(rsIndexVec(i)).ready
XSInfo(io.fromDq(i).fire(),
p"pc 0x${Hexadecimal(io.fromDq(i).bits.cf.pc)} leaves Fp dispatch queue $i with nroq ${io.fromDq(i).bits.roqIdx}\n")
XSDebug(io.fromDq(i).valid && !io.fromDq(i).ready,
p"pc 0x${Hexadecimal(io.fromDq(i).bits.cf.pc)} waits at Fp dispatch queue with index $i\n")
}
/**
* Part 5: the second stage of dispatch 2 (send data to reservation station)
*/
val readPortIndexReg = Reg(Vec(exuParameters.FpExuCnt, UInt(log2Ceil(NRFpReadPorts - exuParameters.StuCnt).W)))
val uopReg = Reg(Vec(exuParameters.FpExuCnt, new MicroOp))
val dataValidRegDebug = Reg(Vec(exuParameters.FpExuCnt, Bool()))
for (i <- 0 until exuParameters.FpExuCnt) {
readPortIndexReg(i) := readPortIndex(i)
uopReg(i) := io.enqIQCtrl(i).bits
dataValidRegDebug(i) := io.enqIQCtrl(i).fire()
io.enqIQData(i) := DontCare
io.enqIQData(i).src1 := io.readRf(readPortIndexReg(i)).data
io.enqIQData(i).src2 := io.readRf(readPortIndexReg(i) + 1.U).data
io.enqIQData(i).src3 := io.readRf(readPortIndexReg(i) + 2.U).data
XSDebug(dataValidRegDebug(i),
p"pc 0x${Hexadecimal(uopReg(i).cf.pc)} reads operands from " +
p"(${readPortIndexReg(i) }, ${uopReg(i).psrc1}, ${Hexadecimal(io.enqIQData(i).src1)}), " +
p"(${readPortIndexReg(i)+1.U}, ${uopReg(i).psrc2}, ${Hexadecimal(io.enqIQData(i).src2)}), " +
p"(${readPortIndexReg(i)+2.U}, ${uopReg(i).psrc3}, ${Hexadecimal(io.enqIQData(i).src3)})\n")
}
}
package xiangshan.backend.dispatch
import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import xiangshan.backend.regfile.RfReadPort
import xiangshan.backend.exu._
class Dispatch2Int extends XSModule {
val io = IO(new Bundle() {
val fromDq = Flipped(Vec(dpParams.IntDqDeqWidth, DecoupledIO(new MicroOp)))
val readRf = Vec(NRIntReadPorts, Flipped(new RfReadPort))
val regRdy = Vec(NRIntReadPorts, Input(Bool()))
val numExist = Input(Vec(exuParameters.IntExuCnt, UInt(log2Ceil(IssQueSize).W)))
val enqIQCtrl = Vec(exuParameters.IntExuCnt, DecoupledIO(new MicroOp))
val enqIQData = Vec(exuParameters.IntExuCnt, Output(new ExuInput))
})
/**
* Part 1: generate indexes for reservation stations
*/
assert(exuParameters.JmpCnt == 1)
val jmpIndexGen = Module(new IndexMapping(dpParams.IntDqDeqWidth, exuParameters.JmpCnt, false))
val aluIndexGen = Module(new IndexMapping(dpParams.IntDqDeqWidth, exuParameters.AluCnt, true))
val mduIndexGen = Module(new IndexMapping(dpParams.IntDqDeqWidth, exuParameters.MduCnt, true))
val aluPriority = PriorityGen((0 until exuParameters.AluCnt).map(i => io.numExist(i+exuParameters.JmpCnt)))
val mduPriority = PriorityGen((0 until exuParameters.MduCnt).map(i => io.numExist(i+exuParameters.JmpCnt+exuParameters.AluCnt)))
for (i <- 0 until dpParams.IntDqDeqWidth) {
jmpIndexGen.io.validBits(i) := io.fromDq(i).valid && Exu.jmpExeUnitCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
aluIndexGen.io.validBits(i) := io.fromDq(i).valid && Exu.aluExeUnitCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
mduIndexGen.io.validBits(i) := io.fromDq(i).valid && Exu.mulDivExeUnitCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
XSDebug(io.fromDq(i).valid,
p"int dp queue $i: ${Hexadecimal(io.fromDq(i).bits.cf.pc)} type ${Binary(io.fromDq(i).bits.ctrl.fuType)}\n")
}
jmpIndexGen.io.priority := DontCare
for (i <- 0 until exuParameters.AluCnt) {
aluIndexGen.io.priority(i) := aluPriority(i)
}
for (i <- 0 until exuParameters.MduCnt) {
mduIndexGen.io.priority(i) := mduPriority(i)
}
val allIndexGen = Seq(jmpIndexGen, aluIndexGen, mduIndexGen)
val validVec = allIndexGen.map(_.io.mapping.map(_.valid)).reduceLeft(_ ++ _)
val indexVec = allIndexGen.map(_.io.mapping.map(_.bits)).reduceLeft(_ ++ _)
val rsValidVec = (0 until dpParams.IntDqDeqWidth).map(i => Cat(allIndexGen.map(_.io.reverseMapping(i).valid)).orR())
val rsIndexVec = (0 until dpParams.IntDqDeqWidth).map({i =>
val indexOffset = Seq(0, exuParameters.JmpCnt, exuParameters.JmpCnt + exuParameters.AluCnt)
allIndexGen.zipWithIndex.map{
case (index, j) => Mux(index.io.reverseMapping(i).valid, index.io.reverseMapping(i).bits + indexOffset(j).U, 0.U)
}.reduce(_ | _)
})
for (i <- validVec.indices) {
// XSDebug(p"mapping $i: valid ${validVec(i)} index ${indexVec(i)}\n")
}
for (i <- rsValidVec.indices) {
// XSDebug(p"jmp reverse $i: valid ${jmpIndexGen.io.reverseMapping(i).valid} index ${jmpIndexGen.io.reverseMapping(i).bits}\n")
// XSDebug(p"alu reverse $i: valid ${aluIndexGen.io.reverseMapping(i).valid} index ${aluIndexGen.io.reverseMapping(i).bits}\n")
// XSDebug(p"mdu reverse $i: valid ${mduIndexGen.io.reverseMapping(i).valid} index ${mduIndexGen.io.reverseMapping(i).bits}\n")
// XSDebug(p"reverseMapping $i: valid ${rsValidVec(i)} index ${rsIndexVec(i)}\n")
}
/**
* Part 2: assign regfile read ports
*/
val intStaticIndex = Seq(1, 2, 3, 4)
val intDynamicIndex = Seq(0, 5, 6)
val intStaticMappedValid = intStaticIndex.map(i => validVec(i))
val intDynamicMappedValid = intDynamicIndex.map(i => validVec(i))
val (intReadPortSrc, intDynamicExuSrc) = RegfileReadPortGen(intStaticMappedValid, intDynamicMappedValid)
val intStaticMapped = intStaticIndex.map(i => indexVec(i))
val intDynamicMapped = intDynamicIndex.map(i => indexVec(i))
for (i <- intStaticIndex.indices) {
val index = WireInit(VecInit(intStaticMapped(i) +: intDynamicMapped))
io.readRf(2*i ).addr := io.fromDq(index(intReadPortSrc(i))).bits.psrc1
io.readRf(2*i+1).addr := io.fromDq(index(intReadPortSrc(i))).bits.psrc2
}
val readPortIndex = Wire(Vec(exuParameters.IntExuCnt, UInt(log2Ceil(NRIntReadPorts).W)))
intStaticIndex.zipWithIndex.map({case (index, i) => readPortIndex(index) := (2*i).U})
intDynamicIndex.zipWithIndex.map({case (index, i) => readPortIndex(index) := 2.U * intDynamicExuSrc(i)})
/**
* Part 3: dispatch to reservation stations
*/
for (i <- 0 until exuParameters.IntExuCnt) {
val enq = io.enqIQCtrl(i)
enq.valid := validVec(i)
enq.bits := io.fromDq(indexVec(i)).bits
enq.bits.src1State := io.regRdy(readPortIndex(i))
enq.bits.src2State := io.regRdy(readPortIndex(i) + 1.U)
XSInfo(enq.fire(), p"pc 0x${Hexadecimal(enq.bits.cf.pc)} with type ${enq.bits.ctrl.fuType} " +
p"srcState(${enq.bits.src1State} ${enq.bits.src2State}) " +
p"enters reservation station $i from ${indexVec(i)}\n")
}
/**
* Part 4: response to dispatch queue
*/
for (i <- 0 until dpParams.IntDqDeqWidth) {
io.fromDq(i).ready := rsValidVec(i) && io.enqIQCtrl(rsIndexVec(i)).ready
XSInfo(io.fromDq(i).fire(),
p"pc 0x${Hexadecimal(io.fromDq(i).bits.cf.pc)} leaves Int dispatch queue $i with nroq ${io.fromDq(i).bits.roqIdx}\n")
XSDebug(io.fromDq(i).valid && !io.fromDq(i).ready,
p"pc 0x${Hexadecimal(io.fromDq(i).bits.cf.pc)} waits at Int dispatch queue with index $i\n")
}
/**
* Part 5: the second stage of dispatch 2 (send data to reservation station)
*/
val readPortIndexReg = Reg(Vec(exuParameters.IntExuCnt, UInt(log2Ceil(NRIntReadPorts).W)))
val uopReg = Reg(Vec(exuParameters.IntExuCnt, new MicroOp))
val dataValidRegDebug = Reg(Vec(exuParameters.IntExuCnt, Bool()))
for (i <- 0 until exuParameters.IntExuCnt) {
readPortIndexReg(i) := readPortIndex(i)
uopReg(i) := io.enqIQCtrl(i).bits
dataValidRegDebug(i) := io.enqIQCtrl(i).fire()
io.enqIQData(i) := DontCare
io.enqIQData(i).src1 := Mux(uopReg(i).ctrl.src1Type === SrcType.pc,
uopReg(i).cf.pc, io.readRf(readPortIndexReg(i)).data)
io.enqIQData(i).src2 := Mux(uopReg(i).ctrl.src2Type === SrcType.imm,
uopReg(i).ctrl.imm, io.readRf(readPortIndexReg(i) + 1.U).data)
XSDebug(dataValidRegDebug(i),
p"pc 0x${Hexadecimal(uopReg(i).cf.pc)} reads operands from " +
p"(${readPortIndexReg(i) }, ${uopReg(i).psrc1}, ${Hexadecimal(io.enqIQData(i).src1)}), " +
p"(${readPortIndexReg(i)+1.U}, ${uopReg(i).psrc2}, ${Hexadecimal(io.enqIQData(i).src2)})\n")
}
}
package xiangshan.backend.dispatch
import chisel3._
import chisel3.util._
import xiangshan._
import utils._
import xiangshan.backend.regfile.RfReadPort
import xiangshan.backend.exu._
class Dispatch2Ls extends XSModule {
val io = IO(new Bundle() {
val fromDq = Flipped(Vec(dpParams.LsDqDeqWidth, DecoupledIO(new MicroOp)))
val intRegAddr = Vec(NRMemReadPorts, Output(UInt(PhyRegIdxWidth.W)))
val fpRegAddr = Vec(exuParameters.StuCnt, Output(UInt(PhyRegIdxWidth.W)))
val intRegRdy = Vec(NRMemReadPorts, Input(Bool()))
val fpRegRdy = Vec(exuParameters.StuCnt, Input(Bool()))
val numExist = Input(Vec(exuParameters.LsExuCnt, UInt(log2Ceil(IssQueSize).W)))
val enqIQCtrl = Vec(exuParameters.LsExuCnt, DecoupledIO(new MicroOp))
})
/**
* Part 1: generate indexes for reservation stations
*/
val loadIndexGen = Module(new IndexMapping(dpParams.LsDqDeqWidth, exuParameters.LduCnt, true))
val storeIndexGen = Module(new IndexMapping(dpParams.LsDqDeqWidth, exuParameters.StuCnt, true))
val loadPriority = PriorityGen((0 until exuParameters.LduCnt).map(i => io.numExist(i)))
val storePriority = PriorityGen((0 until exuParameters.StuCnt).map(i => io.numExist(i+exuParameters.LduCnt)))
for (i <- 0 until dpParams.LsDqDeqWidth) {
loadIndexGen.io.validBits(i) := io.fromDq(i).valid && Exu.ldExeUnitCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
storeIndexGen.io.validBits(i) := io.fromDq(i).valid && Exu.stExeUnitCfg.canAccept(io.fromDq(i).bits.ctrl.fuType)
XSDebug(io.fromDq(i).valid,
p"ls dp queue $i: ${Hexadecimal(io.fromDq(i).bits.cf.pc)} type ${Binary(io.fromDq(i).bits.ctrl.fuType)}\n")
}
for (i <- 0 until exuParameters.LduCnt) {
loadIndexGen.io.priority(i) := loadPriority(i)
}
for (i <- 0 until exuParameters.StuCnt) {
storeIndexGen.io.priority(i) := storePriority(i)
}
val allIndexGen = Seq(loadIndexGen, storeIndexGen)
val validVec = allIndexGen.map(_.io.mapping.map(_.valid)).reduceLeft(_ ++ _)
val indexVec = allIndexGen.map(_.io.mapping.map(_.bits)).reduceLeft(_ ++ _)
val rsValidVec = (0 until dpParams.LsDqDeqWidth).map(i => Cat(allIndexGen.map(_.io.reverseMapping(i).valid)).orR())
val rsIndexVec = (0 until dpParams.LsDqDeqWidth).map({i =>
val indexOffset = Seq(0, exuParameters.LduCnt)
allIndexGen.zipWithIndex.map{
case (index, j) => Mux(index.io.reverseMapping(i).valid, index.io.reverseMapping(i).bits + indexOffset(j).U, 0.U)
}.reduce(_ | _)
})
for (i <- validVec.indices) {
// XSDebug(p"mapping $i: valid ${validVec(i)} index ${indexVec(i)}\n")
}
for (i <- rsValidVec.indices) {
// XSDebug(p"load reverse $i: valid ${loadIndexGen.io.reverseMapping(i).valid} index ${loadIndexGen.io.reverseMapping(i).bits}\n")
// XSDebug(p"store reverse $i: valid ${storeIndexGen.io.reverseMapping(i).valid} index ${storeIndexGen.io.reverseMapping(i).bits}\n")
// XSDebug(p"reverseMapping $i: valid ${rsValidVec(i)} index ${rsIndexVec(i)}\n")
}
/**
* Part 2: assign regfile read ports (actually only reg states from rename)
*
* The four load/store issue queue
*/
assert(exuParameters.LduCnt == 2)
assert(exuParameters.StuCnt == 2)
val readPort = Seq(0, 1, 2, 4)
for (i <- 0 until exuParameters.LsExuCnt) {
if (i < exuParameters.LduCnt) {
io.intRegAddr(readPort(i)) := io.fromDq(indexVec(i)).bits.psrc1
}
else {
io.fpRegAddr(i - exuParameters.LduCnt) := io.fromDq(indexVec(i)).bits.psrc2
io.intRegAddr(readPort(i) ) := io.fromDq(indexVec(i)).bits.psrc1
io.intRegAddr(readPort(i)+1) := io.fromDq(indexVec(i)).bits.psrc2
}
}
/**
* Part 3: dispatch to reservation stations
*/
for (i <- 0 until exuParameters.LsExuCnt) {
val enq = io.enqIQCtrl(i)
// TODO: cache only has 1 load and 1 store
enq.valid := (if (i % 2 == 1) false.B else validVec(i))
enq.bits := io.fromDq(indexVec(i)).bits
enq.bits.src1State := io.intRegRdy(readPort(i))
if (i < exuParameters.LduCnt) {
enq.bits.src2State := DontCare
}
else {
enq.bits.src2State := Mux(io.fromDq(indexVec(i)).bits.ctrl.src1Type === SrcType.fp,
io.fpRegRdy(i - exuParameters.LduCnt), io.intRegRdy(readPort(i) + 1))
}
XSInfo(enq.fire(), p"pc 0x${Hexadecimal(enq.bits.cf.pc)} with type ${enq.bits.ctrl.fuType} " +
p"srcState(${enq.bits.src1State} ${enq.bits.src2State}) " +
p"enters reservation station $i from ${indexVec(i)}\n")
}
/**
* Part 4: response to dispatch queue
*/
for (i <- 0 until dpParams.LsDqDeqWidth) {
// TODO: cache only has 1 load and 1 store
io.fromDq(i).ready := rsValidVec(i) && Mux(rsIndexVec(i)(0) === 1.U, false.B, io.enqIQCtrl(rsIndexVec(i)).ready)
XSInfo(io.fromDq(i).fire(),
p"pc 0x${Hexadecimal(io.fromDq(i).bits.cf.pc)} leaves Ls dispatch queue $i with nroq ${io.fromDq(i).bits.roqIdx}\n")
XSDebug(io.fromDq(i).valid && !io.fromDq(i).ready,
p"pc 0x${Hexadecimal(io.fromDq(i).bits.cf.pc)} waits at Ls dispatch queue with index $i\n")
}
}
package xiangshan.backend.dispatch
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.backend.exu.ExuConfig
import xiangshan.utils.XSDebug
class DispatchGen(exuCfg: Array[ExuConfig]) extends XSModule {
val io = IO(new Bundle() {
// from dispatch queues
val fromIntDq = Flipped(Vec(IntDqDeqWidth, ValidIO(new MicroOp)))
val fromFpDq = Flipped(Vec(FpDqDeqWidth, ValidIO(new MicroOp)))
val fromLsDq = Flipped(Vec(LsDqDeqWidth, ValidIO(new MicroOp)))
// enq Issue Queue
val numExist = Input(Vec(exuParameters.ExuCnt, UInt(log2Ceil(IssQueSize).W)))
val enqIQIndex = Vec(exuParameters.ExuCnt, ValidIO(UInt(log2Ceil(IntDqDeqWidth).W)))
})
assert(IntDqDeqWidth >= FpDqDeqWidth)
assert(IntDqDeqWidth >= LsDqDeqWidth)
def PriorityGen(numExist: Seq[UInt]) = {
assert(numExist.length > 1)
val sortedIndex = Wire(Vec(numExist.length, UInt(log2Ceil(numExist.length).W)))
val priority = WireInit(VecInit(Seq.tabulate(numExist.length)(i => 0.U(log2Ceil(numExist.length).W))))
for (i <- 0 until numExist.length) {
sortedIndex(i) := PriorityEncoder((0 until numExist.length).map(each => {
// itself should not be found yet
val equalPrevious = (if (i == 0) false.B else Cat((0 until i).map(l => each.U === sortedIndex(l))).orR())
val largerThanAnyOther = Cat((0 until numExist.length).map(another => {
// no need to be compared with the larger ones
val anotherEqualPrevious = (if (i == 0) false.B else Cat((0 until i).map(l => another.U === sortedIndex(l))).orR())
// need to be no smaller than any other numbers except the previoud found larger ones
(numExist(each) <= numExist(another)) || anotherEqualPrevious
})).andR()
largerThanAnyOther && !equalPrevious
}))
priority(sortedIndex(i)) := i.U
}
for (i <- 0 until numExist.length) {
XSDebug(p"priority: data($i) = ${numExist(i)}, priority = ${priority(i)}\n")
}
priority
}
def genIQIndex(exunum: Int, deqnum: Int, deq: Seq[Bool], numExist: Seq[UInt]) = {
assert(isPow2(deqnum))
assert(exunum == numExist.length)
// index without priority
val IQIndex = Wire(Vec(exunum, UInt((log2Ceil(deqnum) + 1).W)))
var last_deq = deq
for (i <- 0 until exunum) {
IQIndex(i) := PriorityEncoder(last_deq :+ true.B)
val onehot = UIntToOH(IQIndex(i))
last_deq = (0 until deqnum).map(i => !onehot(i) && last_deq(i))
}
// now consider the IQ priority with numExist
val priority = (if (numExist.length > 1) PriorityGen(numExist) else Seq(0.U))
(0 until exunum).map(i => IQIndex(priority(i)))
}
val intCanAcceptMatrix = io.fromIntDq.map(deq =>
(0 until exuParameters.IntExuCnt).map(i => exuCfg(i).canAccept(deq.bits.ctrl.fuType))
)
val fpCanAcceptMatrix = io.fromFpDq.map(deq =>
(exuParameters.IntExuCnt until exuParameters.IntExuCnt + exuParameters.FpExuCnt).map(i => exuCfg(i).canAccept(deq.bits.ctrl.fuType))
)
val lsCanAcceptMatrix = io.fromFpDq.map(deq =>
(exuParameters.IntExuCnt + exuParameters.FpExuCnt until exuParameters.ExuCnt).map(i => exuCfg(i).canAccept(deq.bits.ctrl.fuType))
)
val bruIQIndex = genIQIndex(exuParameters.JmpCnt, IntDqDeqWidth, intCanAcceptMatrix.map(_(0)),
(0 until exuParameters.JmpCnt).map(i => io.numExist(i)))
val aluIQIndex = genIQIndex(exuParameters.AluCnt, IntDqDeqWidth, intCanAcceptMatrix.map(_(exuParameters.JmpCnt)),
(0 until exuParameters.AluCnt).map(i => io.numExist(exuParameters.JmpCnt+i)))
val mulIQIndex = genIQIndex(exuParameters.MulCnt, IntDqDeqWidth, intCanAcceptMatrix.map(_(exuParameters.JmpCnt+exuParameters.AluCnt)),
(0 until exuParameters.MulCnt).map(i => io.numExist(exuParameters.JmpCnt+exuParameters.AluCnt+i)))
val muldivIQIndex = genIQIndex(exuParameters.MduCnt, IntDqDeqWidth, io.fromIntDq.zipWithIndex.map({case (deq, i) =>
deq.bits.ctrl.fuType === FuType.div || (deq.bits.ctrl.fuType === FuType.mul && i.U > mulIQIndex(0)) }),
(0 until exuParameters.MduCnt).map(i => io.numExist(exuParameters.JmpCnt+exuParameters.AluCnt+exuParameters.MulCnt+i)))
val fmacIQIndex = genIQIndex(exuParameters.FmacCnt, FpDqDeqWidth, if (exuParameters.FmacCnt > 0) fpCanAcceptMatrix.map(_(0)) else Seq(),
(0 until exuParameters.FmacCnt).map(i => io.numExist(exuParameters.IntExuCnt+i)))
val fmiscIQIndex = genIQIndex(exuParameters.FmiscCnt, FpDqDeqWidth, if (exuParameters.FmiscCnt > 0) fpCanAcceptMatrix.map(_(exuParameters.FmacCnt)) else Seq(),
(0 until exuParameters.FmiscCnt).map(i => io.numExist(exuParameters.IntExuCnt+exuParameters.FmacCnt+i)))
val lduIQIndex = genIQIndex(exuParameters.LduCnt, LsDqDeqWidth, lsCanAcceptMatrix.map(_(0)),
(0 until exuParameters.LduCnt).map(i => io.numExist(exuParameters.IntExuCnt+exuParameters.FpExuCnt+i)))
// val stuIQIndex = genIQIndex(exuParameters.StuCnt, LsDqDeqWidth, io.fromLsDq.map(_.bits.ctrl.fuType === FuType.stu))
val stuIQIndex = genIQIndex(exuParameters.StuCnt, LsDqDeqWidth, io.fromLsDq.map(deq => FuType.isMemExu(deq.bits.ctrl.fuType)),
(0 until exuParameters.StuCnt).map(i => io.numExist(exuParameters.IntExuCnt+exuParameters.FpExuCnt+exuParameters.LduCnt+i)))
val allIndex = Seq(bruIQIndex, aluIQIndex, mulIQIndex, muldivIQIndex,
fmacIQIndex, fmiscIQIndex,
lduIQIndex, stuIQIndex
)
val allCnt = Seq(exuParameters.JmpCnt, exuParameters.AluCnt, exuParameters.MulCnt, exuParameters.MduCnt,
exuParameters.FmacCnt, exuParameters.FmiscCnt,
exuParameters.LduCnt, exuParameters.StuCnt
)
assert(allIndex.length == allCnt.length)
var startIndex = 0
for (i <- 0 until allIndex.length) {
for (j <- 0 until allCnt(i)) {
io.enqIQIndex(startIndex + j).valid := !allIndex(i)(j)(2)
io.enqIQIndex(startIndex + j).bits := allIndex(i)(j)(1, 0)
}
startIndex += allCnt(i)
}
}
......@@ -2,96 +2,199 @@ package xiangshan.backend.dispatch
import chisel3._
import chisel3.util._
import xiangshan.utils.{XSDebug, XSInfo}
import xiangshan.{MicroOp, Redirect, XSBundle, XSModule}
import utils.{XSDebug, XSError, XSInfo}
import xiangshan.{MicroOp, Redirect, RoqCommit, XSBundle, XSModule}
class DispatchQueueIO(enqnum: Int, deqnum: Int) extends XSBundle {
val enq = Vec(enqnum, Flipped(DecoupledIO(new MicroOp)))
val deq = Vec(deqnum, DecoupledIO(new MicroOp))
val commits = Input(Vec(CommitWidth, Valid(new RoqCommit)))
val redirect = Flipped(ValidIO(new Redirect))
override def cloneType: DispatchQueueIO.this.type =
new DispatchQueueIO(enqnum, deqnum).asInstanceOf[this.type]
}
class DispatchQueue(size: Int, enqnum: Int, deqnum: Int, name: String) extends XSModule {
// 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, dpqType: Int) extends XSModule {
val io = IO(new DispatchQueueIO(enqnum, deqnum))
val index_width = log2Ceil(size)
val indexWidth = log2Ceil(size)
val s_invalid :: s_valid :: s_dispatched :: Nil = Enum(3)
// queue data array
val entries = Reg(Vec(size, new MicroOp))
val entriesValid = Reg(Vec(size, Bool()))
val head = RegInit(0.U(index_width.W))
val tail = RegInit(0.U(index_width.W))
val enq_index = Wire(Vec(enqnum, UInt(index_width.W)))
val enq_count = Wire(Vec(enqnum, UInt((index_width + 1).W)))
val deq_index = Wire(Vec(deqnum, UInt(index_width.W)))
val head_direction = RegInit(0.U(1.W))
val tail_direction = RegInit(0.U(1.W))
val valid_entries = Mux(head_direction === tail_direction, tail - head, size.U + tail - head)
val empty_entries = size.U - valid_entries
// check whether valid uops are canceled
val cancelled = Wire(Vec(size, Bool()))
for (i <- 0 until size) {
cancelled(i) := entries(i).brTag.needFlush(io.redirect)
val uopEntries = Mem(size, new MicroOp)//Reg(Vec(size, new MicroOp))
val stateEntries = RegInit(VecInit(Seq.fill(size)(s_invalid)))
// head: first valid entry (dispatched entry)
val headPtr = RegInit(0.U((indexWidth + 1).W))
val headIndex = headPtr(indexWidth - 1, 0)
val headDirection = headPtr(indexWidth)
// dispatch: first entry that has not been dispatched
val dispatchPtr = RegInit(0.U((indexWidth + 1).W))
val dispatchIndex = dispatchPtr(indexWidth - 1, 0)
val dispatchDirection = dispatchPtr(indexWidth)
// tail: first invalid entry (free entry)
val tailPtr = RegInit(0.U((indexWidth + 1).W))
val tailIndex = tailPtr(indexWidth - 1, 0)
val tailDirection = tailPtr(indexWidth)
// TODO: make ptr a vector to reduce latency?
// commit: starting from head ptr
val commitPtr = (0 until CommitWidth).map(i => headPtr + i.U)
val commitIndex = commitPtr.map(ptr => ptr(indexWidth - 1, 0))
// deq: starting from dispatch ptr
val deqPtr = (0 until enqnum).map(i => dispatchPtr + i.U)
val deqIndex = deqPtr.map(ptr => ptr(indexWidth - 1, 0))
// enq: starting from tail ptr
val enqPtr = (0 until enqnum).map(i => tailPtr + i.U)
val enqIndex = enqPtr.map(ptr => ptr(indexWidth - 1, 0))
// walkDispatch: in case of redirect, walk backward
val walkDispatchPtr = (0 until RenameWidth).map(i => dispatchPtr - (i + 1).U)
val walkDispatchIndex = walkDispatchPtr.map(ptr => ptr(indexWidth - 1, 0))
// walkTail: in case of redirect, walk backward
val walkTailPtr = (0 until RenameWidth).map(i => tailPtr - (i + 1).U)
val walkTailIndex = walkTailPtr.map(ptr => ptr(indexWidth - 1, 0))
// debug: dump dispatch queue states
def greaterOrEqualThan(left: UInt, right: UInt) = {
Mux(
left(indexWidth) === right(indexWidth),
left(indexWidth - 1, 0) >= right(indexWidth - 1, 0),
left(indexWidth - 1, 0) <= right(indexWidth - 1, 0)
)
}
XSError(!greaterOrEqualThan(tailPtr, headPtr), p"assert greaterOrEqualThan(tailPtr: $tailPtr, headPtr: $headPtr) failed\n")
XSError(!greaterOrEqualThan(tailPtr, dispatchPtr), p"assert greaterOrEqualThan(tailPtr: $tailPtr, dispatchPtr: $dispatchPtr) failed\n")
XSError(!greaterOrEqualThan(dispatchPtr, headPtr), p"assert greaterOrEqualThan(dispatchPtr: $dispatchPtr, headPtr: $headPtr) failed\n")
XSDebug(p"head: $headPtr, tail: $tailPtr, dispatch: $dispatchPtr\n")
XSDebug(p"state: ")
stateEntries.reverse.foreach { s =>
XSDebug(false, s === s_invalid, "-")
XSDebug(false, s === s_valid, "v")
XSDebug(false, s === s_dispatched, "d")
}
XSDebug(false, true.B, "\n")
XSDebug(p"ptr: ")
(0 until size).reverse.foreach { i =>
val isPtr = i.U === headIndex || i.U === tailIndex || i.U === dispatchIndex
XSDebug(false, isPtr, "^")
XSDebug(false, !isPtr, " ")
}
XSDebug(false, true.B, "\n")
val validEntries = Mux(headDirection === tailDirection, tailIndex - headIndex, size.U + tailIndex - headIndex)
val dispatchEntries = Mux(dispatchDirection === tailDirection, tailIndex - dispatchIndex, size.U + tailIndex - dispatchIndex)
XSError(validEntries < dispatchEntries, "validEntries should be less than dispatchEntries\n")
val commitEntries = validEntries - dispatchEntries
val emptyEntries = size.U - validEntries
// calcelled uops should be set to invalid from enqueue input
// we don't need to compare their brTags here
/**
* Part 1: update states and uops when enqueue, dequeue, commit, redirect/replay
*/
for (i <- 0 until enqnum) {
enq_count(i) := PopCount(io.enq.slice(0, i + 1).map(_.valid))
enq_index(i) := (tail + enq_count(i) - 1.U) % size.U
when (io.enq(i).fire()) {
entries(enq_index(i)) := io.enq(i).bits
entriesValid(enq_index(i)) := true.B
uopEntries(enqIndex(i)) := io.enq(i).bits
stateEntries(enqIndex(i)) := s_valid
}
}
for (i <- 0 until deqnum) {
deq_index(i) := ((head + i.U) % size.U).asUInt()
when (io.deq(i).fire()) {
entriesValid(deq_index(i)) := false.B
stateEntries(deqIndex(i)) := s_dispatched
XSError(stateEntries(deqIndex(i)) =/= s_valid, "state of the dispatch entry is not s_valid\n")
}
}
// commit: from s_dispatched to s_invalid
val numCommit = PopCount(io.commits.map(commit => !commit.bits.isWalk && commit.valid && commit.bits.uop.ctrl.dpqType === dpqType.U))
val commitBits = (1.U((CommitWidth+1).W) << numCommit).asUInt() - 1.U
for (i <- 0 until CommitWidth) {
when (commitBits(i)) {
stateEntries(commitIndex(i)) := s_invalid
XSError(stateEntries(commitIndex(i)) =/= s_dispatched, "state of the commit entry is not s_dispatched\n")
}
}
// cancel uops currently in the queue
// redirect: cancel uops currently in the queue
val exceptionValid = io.redirect.valid && io.redirect.bits.isException
val roqNeedFlush = Wire(Vec(size, Bool()))
for (i <- 0 until size) {
when (cancelled(i) && entriesValid(i)) {
entriesValid(i) := false.B
roqNeedFlush(i) := uopEntries(i.U).needFlush(io.redirect)
val needCancel = stateEntries(i) =/= s_invalid && ((roqNeedFlush(i) && io.redirect.bits.isMisPred) || exceptionValid)
when (needCancel) {
stateEntries(i) := s_invalid
}
XSInfo(cancelled(i) && entriesValid(i),
name + ": valid entry(%d)(pc = %x) cancelled with brTag %x\n",
i.U, entries(i).cf.pc, io.redirect.bits.brTag.value)
XSInfo(needCancel, p"valid entry($i)(pc = ${Hexadecimal(uopEntries(i.U).cf.pc)}) " +
p"cancelled with roqIndex ${Hexadecimal(io.redirect.bits.roqIdx)}\n")
}
// replay: from s_dispatched to s_valid
val needReplay = Wire(Vec(size, Bool()))
for (i <- 0 until size) {
needReplay(i) := roqNeedFlush(i) && stateEntries(i) === s_dispatched && io.redirect.bits.isReplay
when (needReplay(i)) {
stateEntries(i) := s_valid
}
XSInfo(needReplay(i), p"dispatched entry($i)(pc = ${Hexadecimal(uopEntries(i.U).cf.pc)}) " +
p"replayed with roqIndex ${Hexadecimal(io.redirect.bits.roqIdx)}\n")
}
/**
* Part 2: update indices
*
* tail: (1) enqueue; (2) walk in case of redirect
* dispatch: (1) dequeue; (2) replay; (3) walk in case of redirect
* head: commit
*/
// enqueue
val num_enq_try = enq_count(enqnum - 1)
val num_enq = Mux(empty_entries > num_enq_try, num_enq_try, empty_entries)
(0 until enqnum).map(i => io.enq(i).ready := enq_count(i) <= num_enq)
tail := (tail + num_enq) % size.U
tail_direction := ((Cat(0.U(1.W), tail) + num_enq) >= size.U).asUInt() ^ tail_direction
val numEnqTry = Mux(emptyEntries > enqnum.U, enqnum.U, emptyEntries)
val numEnq = PriorityEncoder(io.enq.map(!_.fire()) :+ true.B)
val numWalkTailTry = PriorityEncoder(walkTailIndex.map(i => stateEntries(i) =/= s_invalid) :+ true.B)
val numWalkTail = Mux(numWalkTailTry > validEntries, validEntries, numWalkTailTry)
XSError(numEnq =/= 0.U && numWalkTail =/= 0.U, "should not enqueue when walk\n")
tailPtr := Mux(exceptionValid, 0.U, tailPtr + Mux(numEnq =/= 0.U, numEnq, -numWalkTail))
// dequeue
val num_deq_try = Mux(valid_entries > deqnum.U, deqnum.U, valid_entries)
val num_deq_fire = PriorityEncoder((io.deq.zipWithIndex map { case (deq, i) =>
!deq.fire() && entriesValid(deq_index(i))
}) :+ true.B)
val num_deq = Mux(num_deq_try > num_deq_fire, num_deq_fire, num_deq_try)
val numDeqTry = Mux(dispatchEntries > deqnum.U, deqnum.U, dispatchEntries)
val numDeqFire = PriorityEncoder(io.deq.zipWithIndex.map{case (deq, i) =>
// For dequeue, the first entry should never be s_invalid
// Otherwise, there should be a redirect and tail walks back
// in this case, we set numDeq to 0
!deq.fire() && (if (i == 0) true.B else stateEntries(deqIndex(i)) =/= s_dispatched)
} :+ true.B)
val numDeq = Mux(numDeqTry > numDeqFire, numDeqFire, numDeqTry)
// TODO: this is unaccptable since it needs to add 64 bits
val headMask = (1.U((size+1).W) << headIndex) - 1.U
val dispatchMask = (1.U((size + 1).W) << dispatchIndex) - 1.U
val mask = headMask ^ dispatchMask
val replayMask = Mux(headDirection === dispatchDirection, mask, ~mask)
val numReplay = PopCount((0 until size).map(i => needReplay(i) & replayMask(i)))
val numWalkDispatchTry = PriorityEncoder(walkDispatchPtr.map(i => stateEntries(i) =/= s_invalid) :+ true.B)
val numWalkDispatch = Mux(numWalkDispatchTry > commitEntries, commitEntries, numWalkDispatchTry)
val walkCntDispatch = numWalkDispatch + numReplay
// note that numDeq === 0.U entries after dispatch are all flushed
// so, numDeq and walkCntDispatch cannot be nonzero at the same time
XSError(numDeq =/= 0.U && walkCntDispatch =/= 0.U, "should not dequeue when walk\n")
dispatchPtr := Mux(exceptionValid, 0.U, dispatchPtr + Mux(numDeq =/= 0.U, numDeq, -walkCntDispatch))
headPtr := Mux(exceptionValid, 0.U, headPtr + numCommit)
/**
* Part 3: set output and input
*/
val enqReadyBits = (1.U << numEnqTry).asUInt() - 1.U
for (i <- 0 until enqnum) {
io.enq(i).ready := enqReadyBits(i).asBool()
}
for (i <- 0 until deqnum) {
io.deq(i).bits := entries(deq_index(i))
// needs to cancel uops trying to dequeue
io.deq(i).valid := (i.U < num_deq_try) && entriesValid(deq_index(i)) && !cancelled(deq_index(i))
io.deq(i).bits := uopEntries(deqIndex(i))
// do not dequeue when io.redirect valid because it may cause dispatchPtr work improperly
io.deq(i).valid := stateEntries(deqIndex(i)) === s_valid && !io.redirect.valid
}
head := (head + num_deq) % size.U
head_direction := ((Cat(0.U(1.W), head) + num_deq) >= size.U).asUInt() ^ head_direction
XSDebug(num_deq > 0.U, name + ": num_deq = %d, head = (%d -> %d)\n",
num_deq, head, (head + num_deq) % size.U)
XSDebug(num_enq > 0.U, name + ": num_enq = %d, tail = (%d -> %d)\n",
num_enq, tail, (tail + num_enq) % size.U)
XSDebug(valid_entries > 0.U, name + ": valid_entries = %d, head = (%d, %d), tail = (%d, %d), \n",
valid_entries, head_direction, head, tail_direction, tail)
}
package xiangshan.backend.dispatch
import chisel3._
import chisel3.util._
import xiangshan._
import utils._
class IndexMapping(inWidth: Int, outWidth: Int, withPriority: Boolean) extends XSModule {
val io = IO(new Bundle() {
val validBits = Input(Vec(inWidth, Bool()))
val priority = Input(Vec(outWidth, UInt(log2Ceil(outWidth).W)))
val mapping = Output(Vec(outWidth, ValidIO(UInt(log2Ceil(inWidth).W))))
val reverseMapping = Output(Vec(inWidth, ValidIO(UInt(log2Ceil(outWidth).W))))
})
for (j <- 0 until inWidth) {
io.reverseMapping(j).valid := false.B
io.reverseMapping(j).bits := DontCare
}
val unsortedMapping = Wire(Vec(outWidth, UInt(log2Ceil(inWidth).W)))
val unsortedValid = Wire(Vec(outWidth, Bool()))
var maskedValidBits = (0 until inWidth).map(i => io.validBits(i))
for (i <- 0 until outWidth) {
val onehot = PriorityEncoderOH(maskedValidBits)
unsortedValid(i) := Cat(onehot).orR()
unsortedMapping(i) := OHToUInt(onehot)
maskedValidBits = (0 until inWidth).map(i => maskedValidBits(i) && !onehot(i))
val index = if (withPriority) io.priority(i) else i.U
io.mapping(i).valid := unsortedValid(index)
io.mapping(i).bits := unsortedMapping(index)
for (j <- 0 until inWidth) {
when (io.mapping(i).valid && io.mapping(i).bits === j.U) {
io.reverseMapping(j).valid := true.B
io.reverseMapping(j).bits := i.U
}
}
}
}
object PriorityGen {
def apply(numExist: Seq[UInt]) = {
assert(numExist.length > 1)
val sortedIndex = Wire(Vec(numExist.length, UInt(log2Ceil(numExist.length).W)))
val priority = WireInit(VecInit(Seq.tabulate(numExist.length)(_ => 0.U(log2Ceil(numExist.length).W))))
for (i <- numExist.indices) {
sortedIndex(i) := PriorityEncoder(numExist.indices.map(each => {
// itself should not be found yet
val equalPrevious = (if (i == 0) false.B else Cat((0 until i).map(l => each.U === sortedIndex(l))).orR())
val largerThanAnyOther = Cat(numExist.indices.map(another => {
// no need to be compared with the larger ones
val anotherEqualPrevious = (if (i == 0) false.B else Cat((0 until i).map(l => another.U === sortedIndex(l))).orR())
// need to be no smaller than any other numbers except the previoud found larger ones
(numExist(each) <= numExist(another)) || anotherEqualPrevious
})).andR()
largerThanAnyOther && !equalPrevious
}))
priority(sortedIndex(i)) := i.U
}
priority
}
}
object RegfileReadPortGen {
def apply(staticMappedValid: Seq[Bool], dynamicMappedValid: Seq[Bool]) = {
val choiceCount = dynamicMappedValid.length + 1
val readPortSrc = Wire(Vec(staticMappedValid.length, UInt(log2Ceil(choiceCount).W)))
var hasAssigned = (0 until choiceCount).map(_ => false.B)
for (i <- 0 until staticMappedValid.length) {
val valid = staticMappedValid(i) +: dynamicMappedValid
val wantReadPort = (0 until choiceCount).map(j => valid(j) && ((j == 0).asBool() || !hasAssigned(j)))
readPortSrc(i) := PriorityEncoder(wantReadPort)
val onehot = UIntToOH(readPortSrc(i))
hasAssigned = (0 until choiceCount).map(i => hasAssigned(i) || onehot(i))
}
val dynamicExuSrc = Wire(Vec(dynamicMappedValid.length, UInt(log2Ceil(staticMappedValid.length).W)))
for (i <- 0 until dynamicMappedValid.length) {
val targetMatch = (0 until staticMappedValid.length).map(j => readPortSrc(j) === (i + 1).U)
dynamicExuSrc(i) := PriorityEncoder(targetMatch)
}
(readPortSrc, dynamicExuSrc)
}
}
package xiangshan.backend.dispatch
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils.{XSDebug}
class RegfileReadPortGen extends XSModule {
val io = IO(new Bundle() {
// from dispatch queues
val intIQEnqIndex = Flipped(Vec(exuParameters.IntExuCnt, ValidIO(UInt(log2Ceil(IntDqDeqWidth).W))))
val fpIQEnqIndex = Flipped(Vec(exuParameters.FpExuCnt, ValidIO(UInt(log2Ceil(FpDqDeqWidth).W))))
val lsIQEnqIndex = Flipped(Vec(exuParameters.LduCnt + exuParameters.StuCnt, ValidIO(UInt(log2Ceil(LsDqDeqWidth).W))))
// chooses dispatch queue dequeue indexs for regfile read ports
val readIntRf = Output(Vec(NRReadPorts, UInt(log2Ceil(IntDqDeqWidth).W)))
val readFpRf = Output(Vec(NRReadPorts, UInt(log2Ceil(IntDqDeqWidth).W)))
// chooses regfile read ports for reservation stations
val intIQRfSrc = Output(Vec(exuParameters.IntExuCnt, UInt(log2Ceil(NRReadPorts).W)))
val fpIQRfSrc = Output(Vec(exuParameters.FpExuCnt, UInt(log2Ceil(NRReadPorts).W)))
val lsIQRfSrc = Output(Vec(exuParameters.LsExuCnt, UInt(log2Ceil(NRReadPorts).W)))
})
def RegfileReadPortArbiter(staticMappedValid: Seq[Bool], dynamicMappedValid: Seq[Bool]) = {
val choiceCount = dynamicMappedValid.length + 1
// read port is assigned to readPortSrc
val readPortSrc = Wire(Vec(staticMappedValid.length, UInt(log2Ceil(choiceCount).W)))
var hasAssigned = (0 until choiceCount).map(_ => false.B)
for (i <- 0 until staticMappedValid.length) {
val valid = staticMappedValid(i) +: dynamicMappedValid
val wantReadPort = (0 until choiceCount).map(j => valid(j) && ((j == 0).asBool() || !hasAssigned(j)))
readPortSrc(i) := PriorityEncoder(wantReadPort)
val onehot = UIntToOH(readPortSrc(i))
hasAssigned = (0 until choiceCount).map(i => hasAssigned(i) || onehot(i))
XSDebug("int %d: want %b, deqChoice: %d\n", i.U, Cat(wantReadPort), readPortSrc(i))
}
val dynamicExuSrc = Wire(Vec(dynamicMappedValid.length, UInt(log2Ceil(staticMappedValid.length).W)))
for (i <- 0 until dynamicMappedValid.length) {
val targetMatch = (0 until staticMappedValid.length).map(j => readPortSrc(j) === (i + 1).U)
dynamicExuSrc(i) := PriorityEncoder(targetMatch)
XSDebug(p"dynamicExuSrc $i: ${dynamicExuSrc(i)} ${Binary(Cat(targetMatch))}\n")
}
(readPortSrc, dynamicExuSrc)
}
val intStaticIndex = Seq(1, 2, 3, 4)
val intDynamicIndex = Seq(0, 5, 6)
val intStaticMappedValid = intStaticIndex.map(i => io.intIQEnqIndex(i).valid)
val intDynamicMappedValid = intDynamicIndex.map(i => io.intIQEnqIndex(i).valid)
val (intReadPortSrc, intDynamicExuSrc) = RegfileReadPortArbiter(intStaticMappedValid, intDynamicMappedValid)
val intStaticMapped = intStaticIndex.map(i => io.intIQEnqIndex(i).bits)
val intDynamicMapped = intDynamicIndex.map(i => io.intIQEnqIndex(i).bits)
for (i <- 0 until intStaticIndex.length) {
val index = WireInit(VecInit(intStaticMapped(i) +: intDynamicMapped))
io.readIntRf(2*i) := index(intReadPortSrc(i))
io.readIntRf(2*i + 1) := index(intReadPortSrc(i))
}
intStaticIndex.zipWithIndex.map({case (index, i) => io.intIQRfSrc(index) := (2*i).U})
intDynamicIndex.zipWithIndex.map({case (index, i) => io.intIQRfSrc(index) := 2.U * intDynamicExuSrc(i)})
if (exuParameters.FpExuCnt > 0) {
val fpStaticIndex = 0 until exuParameters.FmacCnt
val fpDynamicIndex = exuParameters.FmacCnt until exuParameters.FpExuCnt
val fpStaticMappedValid = fpStaticIndex.map(i => io.fpIQEnqIndex(i).valid)
val fpDynamicMappedValid = fpDynamicIndex.map(i => io.fpIQEnqIndex(i).valid)
val (fpReadPortSrc, fpDynamicExuSrc) = RegfileReadPortArbiter(fpStaticMappedValid, fpDynamicMappedValid)
val fpStaticMapped = fpStaticIndex.map(i => io.fpIQEnqIndex(i).bits)
val fpDynamicMapped = fpDynamicIndex.map(i => io.fpIQEnqIndex(i).bits)
for (i <- 0 until fpStaticIndex.length) {
val index = WireInit(VecInit(fpStaticMapped(i) +: fpDynamicMapped))
io.readFpRf(i) := index(fpReadPortSrc(i))
io.fpIQRfSrc(fpStaticIndex(i)) := (3 * i).U
}
fpDynamicIndex.zipWithIndex.map({ case (index, i) => io.fpIQRfSrc(index) := 3.U * fpDynamicExuSrc(i) })
}
else {
io.fpIQRfSrc <> DontCare
io.readFpRf <> DontCare
}
val lsStaticIndex = 0 until exuParameters.LsExuCnt
val lsDynamicIndex = 0 until 0
val lsStaticMappedValid = lsStaticIndex.map(i => io.lsIQEnqIndex(i).valid)
val lsDynamicMappedValid = lsDynamicIndex.map(i => io.lsIQEnqIndex(i).valid)
val (lsReadPortSrc, lsDynamicExuSrc) = RegfileReadPortArbiter(lsStaticMappedValid, lsDynamicMappedValid)
val lsStaticMapped = lsStaticIndex.map(i => io.lsIQEnqIndex(i).bits)
val lsDynamicMapped = lsDynamicIndex.map(i => io.lsIQEnqIndex(i).bits)
for (i <- 0 until lsStaticIndex.length) {
val index = WireInit(VecInit(lsStaticMapped(i) +: lsDynamicMapped))
if (i < exuParameters.LduCnt) {
val start = intStaticIndex.length*2
io.readIntRf(start+i) := index(lsReadPortSrc(i))
io.lsIQRfSrc(lsStaticIndex(i)) := (start + i).U
}
else {
val start = intStaticIndex.length*2 + exuParameters.LduCnt
io.readIntRf(start + 2 * i) := index(lsReadPortSrc(i))
io.readIntRf(start + 2 * i + 1) := index(lsReadPortSrc(i))
io.lsIQRfSrc(lsStaticIndex(i)) := (start + 2 * i).U
}
}
assert(lsDynamicIndex.length == 0)
val usedPorts = intStaticIndex.length*2 +exuParameters.LduCnt +exuParameters.StuCnt*2
for (i <- usedPorts until NRReadPorts) {
io.readIntRf(i) := DontCare
}
}
......@@ -4,7 +4,7 @@ import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.FuType._
import xiangshan.utils._
import utils._
import xiangshan.backend._
import xiangshan.backend.fu.FunctionUnit._
......@@ -14,7 +14,7 @@ class AluExeUnit extends Exu(Exu.aluExeUnitCfg) {
val (iovalid, src1, src2, offset, func, pc, uop) = (io.in.valid, io.in.bits.src1, io.in.bits.src2,
io.in.bits.uop.ctrl.imm, io.in.bits.uop.ctrl.fuOpType, SignExt(io.in.bits.uop.cf.pc, AddrBits), io.in.bits.uop)
val redirectHit = uop.brTag.needFlush(io.redirect)
val redirectHit = uop.needFlush(io.redirect)
val valid = iovalid && !redirectHit
val isAdderSub = (func =/= ALUOpType.add) && (func =/= ALUOpType.addw) && !ALUOpType.isJump(func)
......@@ -52,16 +52,29 @@ class AluExeUnit extends Exu(Exu.aluExeUnitCfg) {
val isJump = ALUOpType.isJump(func)
val taken = LookupTree(ALUOpType.getBranchType(func), branchOpTable) ^ ALUOpType.isBranchInvert(func)
val target = Mux(isBranch, pc + offset, adderRes)(VAddrBits-1,0)
val isRVC = uop.cf.isRVC//(io.in.bits.cf.instr(1,0) =/= "b11".U)
val isRVC = uop.cf.brUpdate.pd.isRVC//(io.in.bits.cf.instr(1,0) =/= "b11".U)
io.in.ready := io.out.ready
val pcLatchSlot = Mux(isRVC, pc + 2.U, pc + 4.U)
io.out.bits.redirectValid := io.out.valid && isBru//isBranch
io.out.bits.redirect.pc := uop.cf.pc
io.out.bits.redirect.target := Mux(!taken && isBranch, pcLatchSlot, target)
io.out.bits.redirect.brTag := uop.brTag
io.out.bits.redirect.isException := DontCare // false.B
io.out.bits.redirect.isException := false.B
io.out.bits.redirect.isMisPred := DontCare // check this in brq
io.out.bits.redirect.isReplay := false.B
io.out.bits.redirect.roqIdx := uop.roqIdx
io.out.bits.redirect.freelistAllocPtr := uop.freelistAllocPtr
io.out.bits.brUpdate := uop.cf.brUpdate
// override brUpdate
io.out.bits.brUpdate.pc := uop.cf.pc
io.out.bits.brUpdate.target := Mux(!taken && isBranch, pcLatchSlot, target)
io.out.bits.brUpdate.brTarget := target
// io.out.bits.brUpdate.btbType := "b00".U
io.out.bits.brUpdate.taken := isBranch && taken
// io.out.bits.brUpdate.fetchIdx := uop.cf.brUpdate.fetchOffset >> 1.U //TODO: consider RVC
io.out.valid := valid
io.out.bits.uop <> io.in.bits.uop
......@@ -81,6 +94,6 @@ class AluExeUnit extends Exu(Exu.aluExeUnitCfg) {
)
XSDebug(io.in.valid, "src1:%x src2:%x offset:%x func:%b pc:%x\n",
src1, src2, offset, func, pc)
XSDebug(io.out.valid, "res:%x aluRes:%x isRVC:%d isBru:%d isBranch:%d isJump:%d target:%x taken:%d flptr:%x\n",
io.out.bits.data, aluRes, isRVC, isBru, isBranch, isJump, target, taken, io.out.bits.uop.freelistAllocPtr.value)
XSDebug(io.out.valid, "res:%x aluRes:%x isRVC:%d isBru:%d isBranch:%d isJump:%d target:%x taken:%d\n",
io.out.bits.data, aluRes, isRVC, isBru, isBranch, isJump, target, taken)
}
\ No newline at end of file
......@@ -5,7 +5,7 @@ import chisel3.util._
import xiangshan._
import xiangshan.FuType._
import xiangshan.backend.fu.FuConfig
import xiangshan.utils.ParallelOR
import utils.ParallelOR
import xiangshan.backend.fu.FunctionUnit._
case class ExuParameters
......@@ -45,38 +45,26 @@ case class ExuConfig
val hasRedirect = supportedFuncUnits.map(_.hasRedirect).reduce(_||_)
def canAccept(fuType: UInt): Bool = {
ParallelOR(supportedFuncUnits.map(_.fuType === fuType)).asBool()
ParallelOR(supportedFuncUnits.map(_.fuType === fuType))
}
}
abstract class Exu(val config: ExuConfig) extends XSModule {
val io = IO(new ExuIO)
io.dmem <> DontCare
io.out.bits.brUpdate <> DontCare
io.out.bits.debug.isMMIO := false.B
}
object Exu {
val jmpExeUnitCfg = ExuConfig("JmpExu", Array(jmpCfg, i2fCfg), enableBypass = false)
val jmpExeUnitCfg = ExuConfig("JmpExu", Array(jmpCfg, i2fCfg, csrCfg), enableBypass = false)
val aluExeUnitCfg = ExuConfig("AluExu", Array(aluCfg), enableBypass = true)
val mulExeUnitCfg = ExuConfig("MulExu", Array(mulCfg), enableBypass = false)
val divExeUnitCfg = ExuConfig("DivExu",Array(divCfg), enableBypass = false)
val mulDivExeUnitCfg = ExuConfig("MulDivExu", Array(mulCfg, divCfg), enableBypass = false)
val lsuExeUnitCfg = ExuConfig("LsExu", Array(lsuCfg), enableBypass = false)
}
trait HasExeUnits{
val aluExeUnits = Array.tabulate(exuParameters.AluCnt)(_ => Module(new AluExeUnit))
val jmpExeUnit = Module(new JmpExeUnit)
val mulExeUnits = Array.tabulate(exuParameters.MulCnt)(_ => Module(new MulExeUnit))
val mduExeUnits = Array.tabulate(exuParameters.MduCnt)(_ => Module(new MulDivExeUnit))
// val fmacExeUnits = Array.tabulate(exuParameters.FmacCnt)(_ => Module(new Fmac))
// val fmiscExeUnits = Array.tabulate(exuParameters.FmiscCnt)(_ => Module(new Fmisc))
// val fmiscDivSqrtExeUnits = Array.tabulate(exuParameters.FmiscDivSqrtCnt)(_ => Module(new FmiscDivSqrt))
val lsuExeUnits = Array.tabulate(exuParameters.StuCnt)(_ => Module(new LsExeUnit))
val exeUnits = jmpExeUnit +: (aluExeUnits ++ mulExeUnits ++ mduExeUnits ++ lsuExeUnits)
exeUnits.foreach(_.io.dmem := DontCare)
exeUnits.foreach(_.io.scommit := DontCare)
val ldExeUnitCfg = ExuConfig("LoadExu", Array(lduCfg), enableBypass = false)
val stExeUnitCfg =ExuConfig("StoreExu", Array(stuCfg), enableBypass = false)
val fmacExeUnitCfg = ExuConfig("FmacExu", Array(fmacCfg), enableBypass = false)
val fmiscExeUnitCfg = ExuConfig("FmiscExu", Array(fmiscCfg), enableBypass = false)
val fmiscDivExeUnitCfg = ExuConfig("FmiscDivExu", Array(fmiscCfg, fDivSqrtCfg), enableBypass = false)
}
package xiangshan.backend.exu
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.FuType._
import xiangshan.utils._
import xiangshan.backend.regfile.RfWritePort
import xiangshan.backend.fu.FunctionUnit._
import xiangshan.backend.BRUOpType
import xiangshan.{ExuOutput, FuType}
import xiangshan.backend.fu.{CSR, Jump}
import xiangshan.backend.decode.isa._
import utils._
// NOTE: BRUOpType is at backend/package.scala
// TODO: add csr
class JmpExeUnit extends Exu(Exu.jmpExeUnitCfg) {
val (iovalid, src1, offset, func, pc, uop) = (io.in.valid, io.in.bits.src1, io.in.bits.uop.ctrl.imm, io.in.bits.uop.ctrl.fuOpType, SignExt(io.in.bits.uop.cf.pc, AddrBits), io.in.bits.uop)
val redirectHit = uop.brTag.needFlush(io.redirect)
val valid = iovalid && !redirectHit
val isCSR = BRUOpType.isCSR(func)
val isFMV = BRUOpType.isFMV(func)
val isMOU = BRUOpType.isMOU(func)
val isJUMP = BRUOpType.isJUMP(func)
// CSR
// FMV
// MOU
// JUMP
val isRVC = uop.cf.isRVC
val pcDelaySlot = Mux(isRVC, pc + 2.U, pc + 4.U)
val target = src1 + offset // NOTE: src1 is (pc/rf(rs1)), src2 is (offset)
io.out.bits.redirectValid := valid && isJUMP
io.out.bits.redirect.target := target
io.out.bits.redirect.brTag := uop.brTag
io.out.bits.redirect.isException := false.B
io.out.bits.redirect.roqIdx := uop.roqIdx
io.out.bits.redirect.freelistAllocPtr := uop.freelistAllocPtr
// Output
val resCSR = WireInit(0.U(XLEN.W)) // TODO: implement it
val resFMV = WireInit(0.U(XLEN.W)) // TODO: implement it
val resMOU = WireInit(0.U(XLEN.W)) // TODO: implement it
val resJMP = pcDelaySlot
val res = ParallelMux(
VecInit(isCSR, isFMV, isMOU, isJUMP) zip
VecInit(resCSR, resFMV, resMOU, resJMP)
val jmp = Module(new Jump)
jmp.io.out.ready := io.out.ready
jmp.io.exception <> DontCare
jmp.io.dmem <> DontCare
jmp.io.mcommit := DontCare
jmp.io.redirect := io.redirect
val csr = Module(new CSR)
csr.io.cfIn := io.in.bits.uop.cf
csr.io.fpu_csr := DontCare
csr.io.exception <> io.exception
csr.io.instrValid := DontCare
csr.io.imemMMU := DontCare
csr.io.dmemMMU := DontCare
csr.io.out.ready := io.out.ready
csr.io.in.bits.src3 := DontCare
val csrOut = csr.access(
valid = io.in.valid && io.in.bits.uop.ctrl.fuType===FuType.csr,
src1 = io.in.bits.src1,
src2 = io.in.bits.src2,
func = io.in.bits.uop.ctrl.fuOpType
)
val uop = io.in.bits.uop
val csrExuOut = Wire(new ExuOutput)
csrExuOut.uop := uop
csrExuOut.uop.cf := csr.io.cfOut
csrExuOut.data := csrOut
csrExuOut.redirectValid := csr.io.redirectValid
csrExuOut.redirect.brTag := uop.brTag
csrExuOut.redirect.isException := false.B
csrExuOut.redirect.isMisPred := false.B
csrExuOut.redirect.isReplay := false.B
csrExuOut.redirect.roqIdx := uop.roqIdx
csrExuOut.redirect.target := csr.io.redirect.target
csrExuOut.redirect.pc := uop.cf.pc
csrExuOut.debug := DontCare
csrExuOut.brUpdate := DontCare
jmp.io.in.bits := io.in.bits
jmp.io.in.valid := io.in.valid && io.in.bits.uop.ctrl.fuType===FuType.jmp
io.in.ready := io.out.ready
io.out.valid := valid // TODO: CSR/MOU/FMV may need change it
io.out.bits.uop <> io.in.bits.uop
io.out.bits.data := res
// 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) brTag:%x\n",
io.in.valid, io.in.ready, io.out.valid, io.out.ready, io.redirect.valid, io.redirect.bits.isException, redirectHit, io.redirect.bits.brTag.value)
XSDebug(io.in.valid && isCSR, "src1:%x offset:%x func:%b type:CSR pc:%x\n", src1, offset, func, pc)
XSDebug(io.in.valid && isFMV, "src1:%x offset:%x func:%b type:FMV pc:%x\n", src1, offset, func, pc)
XSDebug(io.in.valid && isMOU, "src1:%x offset:%x func:%b type:MOU pc:%x\n", src1, offset, func, pc)
XSDebug(io.in.valid && isJUMP, "src1:%x offset:%x func:%b type:JUMP pc:%x\n", src1, offset, func, pc)
XSDebug(io.in.valid, "Res:%x` CsrRes:%x FMV:%x Mou:%x Jmp:%x\n", res, resCSR, resFMV, resMOU, resJMP)
io.out.bits := Mux(jmp.io.in.valid, jmp.io.out.bits, csrExuOut)
io.out.valid := io.in.valid
}
\ No newline at end of file
package xiangshan.backend.exu
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import xiangshan._
import utils._
import bus.simplebus._
import xiangshan.AddressSpace
import xiangshan.backend._
import xiangshan.backend.brq.BrqPtr
class StoreQueueEntry extends XSBundle{
val src1 = UInt(XLEN.W)
val src2 = UInt(XLEN.W)
val addr = UInt(XLEN.W)
val src3 = UInt(XLEN.W)
val wdata = UInt(XLEN.W)
val func = UInt(6.W)
val pc = UInt(VAddrBits.W) //for debug
val brTag = new BrqPtr //FIXIT
}
// Multi-cycle LSU ported from NOOP
class LsExeUnit extends Exu(Exu.lsuExeUnitCfg){
// store buffer
val stqData = Reg(Vec(8, new StoreQueueEntry))
val stqValid = RegInit(VecInit(List.fill(8)(false.B)))
val stqPtr = Reg(Vec(8, UInt(3.W)))
val stqHead = RegInit(0.U(3.W))
val stqTail = stqPtr(0)
val stqCommited = RegInit(0.U(3.W))
val stqFull = stqHead === 7.U //stq_valid.reduce(_.valid && _.valid)
val emptySlot = PriorityMux(~stqValid.asUInt, VecInit(List.tabulate(8)(_.U)))
// when retiringStore, block all input insts
val isStoreIn = io.in.valid && LSUOpType.isStore(io.in.bits.uop.ctrl.fuOpType)
val retiringStore = RegInit(false.B)
val (validIn, src1In, src2In, src3In, funcIn) = (io.in.valid, io.in.bits.src1, io.in.bits.uop.ctrl.imm, io.in.bits.src2, io.in.bits.uop.ctrl.fuOpType)
val (valid, src1, src2, wdata, func) =
(
Mux(retiringStore, stqValid(stqTail), validIn && !isStoreIn),
Mux(retiringStore, stqData(stqTail).src1, src1In),
Mux(retiringStore, stqData(stqTail).src2, src2In),
Mux(retiringStore, stqData(stqTail).src3, src3In),
Mux(retiringStore, stqData(stqTail).func, funcIn)
)
assert(!(retiringStore && !stqValid(stqTail)))
def genWmask(addr: UInt, sizeEncode: UInt): UInt = {
LookupTree(sizeEncode, List(
"b00".U -> 0x1.U, //0001 << addr(2:0)
"b01".U -> 0x3.U, //0011
"b10".U -> 0xf.U, //1111
"b11".U -> 0xff.U //11111111
)) << addr(2, 0)
}
def genWdata(data: UInt, sizeEncode: UInt): UInt = {
LookupTree(sizeEncode, List(
"b00".U -> Fill(8, data(7, 0)),
"b01".U -> Fill(4, data(15, 0)),
"b10".U -> Fill(2, data(31, 0)),
"b11".U -> data
))
}
val dmem = io.dmem
val addr = src1 + src2
val addrLatch = RegNext(addr)
val isStore = valid && LSUOpType.isStore(func)
val partialLoad = !isStore && (func =/= LSUOpType.ld)
val s_idle :: s_wait_resp :: s_partialLoad :: Nil = Enum(3)
val state = RegInit(s_idle)
switch (state) {
is (s_idle) { when (dmem.req.fire()) { state := Mux(isStore, s_partialLoad, s_wait_resp) } }
is (s_wait_resp) { when (dmem.resp.fire()) { state := Mux(partialLoad, s_partialLoad, s_idle) } }
is (s_partialLoad) { state := s_idle }
}
val size = func(1,0)
dmem.req.bits.apply(addr = addr, size = size, wdata = genWdata(wdata, size),
wmask = genWmask(addr, size), cmd = Mux(isStore, SimpleBusCmd.write, SimpleBusCmd.read))
dmem.req.valid := valid && (state === s_idle)
dmem.resp.ready := true.B
XSDebug("state %x req.valid/ready %x/%x resp.valid/ready %x/%x addr %x size %x data %x mask %x cmd %x\n",
state, dmem.req.valid, dmem.req.ready, dmem.resp.valid, dmem.resp.ready,
addr, size, genWdata(wdata, size), genWmask(addr, size), Mux(isStore, SimpleBusCmd.write, SimpleBusCmd.read)
)
val rdata = Wire(UInt(XLEN.W))
val rdataLatch = RegNext(rdata)
val rdataSel = LookupTree(addrLatch(2, 0), List(
"b000".U -> rdataLatch(63, 0),
"b001".U -> rdataLatch(63, 8),
"b010".U -> rdataLatch(63, 16),
"b011".U -> rdataLatch(63, 24),
"b100".U -> rdataLatch(63, 32),
"b101".U -> rdataLatch(63, 40),
"b110".U -> rdataLatch(63, 48),
"b111".U -> rdataLatch(63, 56)
))
val rdataPartialLoad = LookupTree(func, List(
LSUOpType.lb -> SignExt(rdataSel(7, 0) , XLEN),
LSUOpType.lh -> SignExt(rdataSel(15, 0), XLEN),
LSUOpType.lw -> SignExt(rdataSel(31, 0), XLEN),
LSUOpType.lbu -> ZeroExt(rdataSel(7, 0) , XLEN),
LSUOpType.lhu -> ZeroExt(rdataSel(15, 0), XLEN),
LSUOpType.lwu -> ZeroExt(rdataSel(31, 0), XLEN)
))
// pop store queue if insts have been commited and dmem req fired successfully
val storeFinish = retiringStore && state === s_partialLoad
val stqDequeue = storeFinish || !stqValid(stqTail) && stqHead > 0.U
when(stqDequeue){
stqValid(stqTail) := false.B
// update stq ptr
for(i <- 1 until 8){
stqPtr(i-1) := stqPtr(i)
}
}
// if store, add it to store queue
val stqEnqueue = validIn && isStoreIn && !stqFull && !retiringStore && !io.redirect.valid
when(stqEnqueue){
stqPtr(stqHead) := emptySlot
stqData(emptySlot).src1 := src1In
stqData(emptySlot).src2 := src2In
stqData(emptySlot).addr := src1In + src2In
stqData(emptySlot).src3 := genWdata(src3In, funcIn(1, 0))
stqData(emptySlot).pc := io.in.bits.uop.cf.pc
stqData(emptySlot).func := funcIn
stqData(emptySlot).brTag := io.in.bits.uop.brTag
stqValid(emptySlot) := true.B
}
// if store insts have been commited, send dmem req
// have to say it seems better to rebuild FSM instead of using such ugly wrapper
val needRetireStore = stqCommited > 0.U && stqValid(stqTail)
when(
needRetireStore && !retiringStore && state === s_idle && !io.in.valid ||
needRetireStore && !retiringStore && io.in.valid && isStoreIn
){
retiringStore := true.B
}
when(state === s_partialLoad && retiringStore){
retiringStore := false.B
}
// update stqTail, stqCommited
stqCommited := stqCommited + io.scommit - storeFinish
stqHead := stqHead + stqEnqueue - stqDequeue
// Store addr forward match
// If match, get data from store queue
val dataBackVec = Wire(Vec(XLEN/8, (UInt((XLEN/8).W))))
for(j <- (0 to (XLEN/8 - 1))){
dataBackVec(j) := dmem.resp.bits.rdata(8*(j+1)-1, 8*j)
}
for(i <- 0 until 8){
when(stqValid(stqPtr(i)) && i.U < stqHead){
when(addr(PAddrBits-1, log2Up(XLEN/8)) === stqData(stqPtr(i)).addr(PAddrBits-1, log2Up(XLEN/8))){
for(j <- (0 to (XLEN/8 - 1))){
when(genWmask(stqData(stqPtr(i)).addr, stqData(stqPtr(i)).func(1, 0))(j)){
dataBackVec(j) := stqData(stqPtr(i)).src3(8*(j+1)-1, 8*j)
XSDebug("forwarding data from stq, addr %x stqpos %d bitpos %d data %x\n", addr, i.U, j.U, stqData(stqPtr(i)).src3(8*(j+1)-1, 8*j))
}
}
}
XSDebug("sbuffer id %d ptr %d pc %x addr %x data %x func %x wmask %b\n",
i.U, stqPtr(i), stqData(stqPtr(i)).pc, stqData(stqPtr(i)).src1 + stqData(stqPtr(i)).src2, stqData(stqPtr(i)).src3, stqData(stqPtr(i)).func, genWmask(stqData(stqPtr(i)).addr, stqData(stqPtr(i)).func(1, 0))
)
}
}
rdata := dataBackVec.asUInt
val expRedirect = io.redirect.valid && io.redirect.bits.isException
val brRedirect = io.redirect.valid && !io.redirect.bits.isException
for(i <- 0 until 8){
when(expRedirect || brRedirect && stqData(i).brTag.needBrFlush(io.redirect.bits.brTag) && stqValid(i)){
stqValid(i) := false.B
}
XSDebug("sptrtable: id %d ptr %d valid %d\n", i.U, stqPtr(i), stqValid(stqPtr(i)))
}
when(expRedirect){
//invalidate uncommited store
//FIXME
}
io.in.ready := io.out.fire()
val validLoad = RegInit(false.B)
when(state =/= s_idle && !io.in.valid) { validLoad := false.B }
when(state === s_idle && io.in.valid && !retiringStore && dmem.req.fire()) { validLoad := true.B }
io.out.valid := (!isStoreIn && !retiringStore && validLoad && Mux(partialLoad, state === s_partialLoad, dmem.resp.fire() && (state === s_wait_resp)) || stqEnqueue) && io.in.valid
io.out.bits.uop <> io.in.bits.uop
io.out.bits.data := Mux(partialLoad, rdataPartialLoad, rdata)
// io.out.bits.debug.isMMIO := AddressSpace.isMMIO(addr) && io.out.valid
io.out.bits.debug.isMMIO := AddressSpace.isMMIO(addr) //for debug
io.out.bits.redirect := DontCare
io.out.bits.redirectValid := false.B
when(io.out.fire()){
XSDebug("LSU fire: pc %x addr %x mmio %x isStoreIn %x retiringStore %x partialLoad %x dmem %x stqEnqueue %x state %x dmemres %x fwdres %x\n",
io.in.bits.uop.cf.pc,
addr,
io.out.bits.debug.isMMIO,
isStoreIn,
retiringStore,
partialLoad,
dmem.resp.fire(),
stqEnqueue,
state,
dmem.resp.bits.rdata,
io.out.bits.data
)
}
// debug
XSDebug("state: %d (valid, ready): in (%d,%d) out (%d,%d)\n", state, io.in.valid, io.in.ready, io.out.valid, io.out.ready)
XSDebug("stqinfo: stqValid.asUInt %b stqHead %d stqTail %d stqCommited %d emptySlot %d\n", stqValid.asUInt, stqHead, stqTail, stqCommited, emptySlot)
XSDebug(retiringStore, "retiringStore now...\n")
XSInfo(io.dmem.req.fire() && io.dmem.req.bits.cmd =/= SimpleBusCmd.write, "[DMEM LOAD REQ] addr 0x%x wdata 0x%x size %d\n", dmem.req.bits.addr, dmem.req.bits.wdata, dmem.req.bits.size)
XSInfo(io.dmem.req.fire() && io.dmem.req.bits.cmd === SimpleBusCmd.write, "[DMEM STORE REQ] addr 0x%x wdata 0x%x size %d\n", dmem.req.bits.addr, dmem.req.bits.wdata, dmem.req.bits.size)
XSInfo(io.dmem.resp.fire(), "[DMEM RESP] data %x\n", rdata)
}
//package xiangshan.backend.exu
//
//import chisel3._
//import chisel3.util._
//import chisel3.util.experimental.BoringUtils
//import xiangshan._
//import utils._
//import bus.simplebus._
//import xiangshan.AddressSpace
//import xiangshan.backend._
//import xiangshan.backend.brq.BrqPtr
//import fpu.boxF32ToF64
//
//
//class StoreQueueEntry extends XSBundle{
// val src1 = UInt(XLEN.W)
// val src2 = UInt(XLEN.W)
// val addr = UInt(XLEN.W)
// val src3 = UInt(XLEN.W)
// val wdata = UInt(XLEN.W)
// val func = UInt(6.W)
// val pc = UInt(VAddrBits.W) //for debug
// val brTag = new BrqPtr //FIXIT
//}
//
//// Multi-cycle LSU ported from NOOP
//class LsExeUnit extends Exu(Exu.lsuExeUnitCfg){
//
// // store buffer
// val stqData = Reg(Vec(8, new StoreQueueEntry))
// val stqValid = RegInit(VecInit(List.fill(8)(false.B)))
// val stqPtr = Reg(Vec(8, UInt(3.W)))
// val stqHead = RegInit(0.U(3.W))
// val stqTail = stqPtr(0)
// val stqCommited = RegInit(0.U(3.W))
// val stqFull = stqHead === 7.U //stq_valid.reduce(_.valid && _.valid)
// val emptySlot = PriorityMux(~stqValid.asUInt, VecInit(List.tabulate(8)(_.U)))
//
// // when retiringStore, block all input insts
// val isStoreIn = io.in.valid && LSUOpType.isStore(io.in.bits.uop.ctrl.fuOpType)
// val retiringStore = RegInit(false.B)
// val (validIn, src1In, src2In, src3In, funcIn) = (io.in.valid, io.in.bits.src1, io.in.bits.uop.ctrl.imm, io.in.bits.src2, io.in.bits.uop.ctrl.fuOpType)
// val (valid, src1, src2, wdata, func) =
// (
// Mux(retiringStore, stqValid(stqTail), validIn && !isStoreIn),
// Mux(retiringStore, stqData(stqTail).src1, src1In),
// Mux(retiringStore, stqData(stqTail).src2, src2In),
// Mux(retiringStore, stqData(stqTail).src3, src3In),
// Mux(retiringStore, stqData(stqTail).func, funcIn)
// )
// // assert(!(retiringStore && !stqValid(stqTail)))
//
// def genWmask(addr: UInt, sizeEncode: UInt): UInt = {
// LookupTree(sizeEncode, List(
// "b00".U -> 0x1.U, //0001 << addr(2:0)
// "b01".U -> 0x3.U, //0011
// "b10".U -> 0xf.U, //1111
// "b11".U -> 0xff.U //11111111
// )) << addr(2, 0)
// }
// def genWdata(data: UInt, sizeEncode: UInt): UInt = {
// LookupTree(sizeEncode, List(
// "b00".U -> Fill(8, data(7, 0)),
// "b01".U -> Fill(4, data(15, 0)),
// "b10".U -> Fill(2, data(31, 0)),
// "b11".U -> data
// ))
// }
//
// val dmem = io.dmem
// val addr = src1 + src2
// val addrLatch = RegNext(addr)
// val isStore = valid && LSUOpType.isStore(func)
// val partialLoad = !isStore && (func =/= LSUOpType.ld)
//
// val s_idle :: s_wait_resp :: s_partialLoad :: Nil = Enum(3)
// val state = RegInit(s_idle)
//
// switch (state) {
// is (s_idle) { when (dmem.req.fire()) { state := Mux(isStore, s_partialLoad, s_wait_resp) } }
// is (s_wait_resp) { when (dmem.resp.fire()) { state := Mux(partialLoad, s_partialLoad, s_idle) } }
// is (s_partialLoad) { state := s_idle }
// }
//
// val size = func(1,0)
// dmem.req.bits.apply(addr = addr, size = size, wdata = genWdata(wdata, size),
// wmask = genWmask(addr, size), cmd = Mux(isStore, SimpleBusCmd.write, SimpleBusCmd.read))
// dmem.req.valid := valid && (state === s_idle)
// dmem.resp.ready := true.B
//
// XSDebug("state %x req.valid/ready %x/%x resp.valid/ready %x/%x addr %x size %x data %x mask %x cmd %x\n",
// state, dmem.req.valid, dmem.req.ready, dmem.resp.valid, dmem.resp.ready,
// addr, size, genWdata(wdata, size), genWmask(addr, size), Mux(isStore, SimpleBusCmd.write, SimpleBusCmd.read)
// )
//
// val rdata = Wire(UInt(XLEN.W))
// val rdataLatch = RegNext(rdata)
// val rdataSel = LookupTree(addrLatch(2, 0), List(
// "b000".U -> rdataLatch(63, 0),
// "b001".U -> rdataLatch(63, 8),
// "b010".U -> rdataLatch(63, 16),
// "b011".U -> rdataLatch(63, 24),
// "b100".U -> rdataLatch(63, 32),
// "b101".U -> rdataLatch(63, 40),
// "b110".U -> rdataLatch(63, 48),
// "b111".U -> rdataLatch(63, 56)
// ))
// val rdataPartialLoad = LookupTree(func, List(
// LSUOpType.lb -> SignExt(rdataSel(7, 0) , XLEN),
// LSUOpType.lh -> SignExt(rdataSel(15, 0), XLEN),
// LSUOpType.lw -> SignExt(rdataSel(31, 0), XLEN),
// LSUOpType.lbu -> ZeroExt(rdataSel(7, 0) , XLEN),
// LSUOpType.lhu -> ZeroExt(rdataSel(15, 0), XLEN),
// LSUOpType.lwu -> ZeroExt(rdataSel(31, 0), XLEN),
// LSUOpType.flw -> boxF32ToF64(rdataSel(31,0))
// ))
//
// // pop store queue if insts have been commited and dmem req fired successfully
// val storeFinish = retiringStore && dmem.resp.fire()//state === s_partialLoad
// val stqDequeue = storeFinish || !stqValid(stqTail) && stqHead > 0.U
// when(stqDequeue){
// stqValid(stqTail) := false.B
// // update stq ptr
// for(i <- 1 until 8){
// stqPtr(i-1) := stqPtr(i)
// }
// }
//
// // if store, add it to store queue
// val stqEnqueue = validIn && isStoreIn && !stqFull && !retiringStore && !io.redirect.valid && state === s_idle
// when(stqEnqueue){
// stqPtr(stqHead - stqDequeue) := emptySlot
// stqData(emptySlot).src1 := src1In
// stqData(emptySlot).src2 := src2In
// stqData(emptySlot).addr := src1In + src2In
// stqData(emptySlot).src3 := genWdata(src3In, funcIn(1, 0))
// stqData(emptySlot).pc := io.in.bits.uop.cf.pc
// stqData(emptySlot).func := funcIn
// stqData(emptySlot).brTag := io.in.bits.uop.brTag
// stqValid(emptySlot) := true.B
// }
//
// // if store insts have been commited, send dmem req
// // have to say it seems better to rebuild FSM instead of using such ugly wrapper
// val needRetireStore = stqCommited > 0.U && stqValid(stqTail)
// when(
// needRetireStore && !retiringStore && state === s_idle && (!io.in.valid || isStoreIn)
// ){
// retiringStore := true.B
// }
// when(dmem.resp.fire() && retiringStore){
// retiringStore := false.B
// }
//
// // update stqTail, stqCommited
// stqCommited := stqCommited + io.mcommit - storeFinish
// stqHead := stqHead + stqEnqueue - stqDequeue
//
// // Store addr forward match
// // If match, get data from store queue
// val dataBackVec = Wire(Vec(XLEN/8, (UInt((XLEN/8).W))))
// for(j <- (0 to (XLEN/8 - 1))){
// dataBackVec(j) := dmem.resp.bits.rdata(8*(j+1)-1, 8*j)
// }
//
// for(i <- 0 until 8){
// when(stqValid(stqPtr(i)) && i.U < stqHead){
// when(addr(PAddrBits-1, log2Up(XLEN/8)) === stqData(stqPtr(i)).addr(PAddrBits-1, log2Up(XLEN/8))){
// for(j <- (0 to (XLEN/8 - 1))){
// when(genWmask(stqData(stqPtr(i)).addr, stqData(stqPtr(i)).func(1, 0))(j)){
// dataBackVec(j) := stqData(stqPtr(i)).src3(8*(j+1)-1, 8*j)
// XSDebug("forwarding data from stq, addr %x stqpos %d bitpos %d data %x\n", addr, i.U, j.U, stqData(stqPtr(i)).src3(8*(j+1)-1, 8*j))
// }
// }
// }
// XSDebug("sbuffer id %d ptr %d pc %x addr %x data %x func %x wmask %b\n",
// i.U, stqPtr(i), stqData(stqPtr(i)).pc, stqData(stqPtr(i)).src1 + stqData(stqPtr(i)).src2, stqData(stqPtr(i)).src3, stqData(stqPtr(i)).func, genWmask(stqData(stqPtr(i)).addr, stqData(stqPtr(i)).func(1, 0))
// )
// }
// }
// rdata := dataBackVec.asUInt
//
// val expRedirect = io.redirect.valid && io.redirect.bits.isException
// val brRedirect = io.redirect.valid && !io.redirect.bits.isException
// for(i <- 0 until 8){
// when((i.U >= stqCommited && i.U < stqHead) && (expRedirect || brRedirect && stqData(stqPtr(i)).brTag.needBrFlush(io.redirect.bits.brTag) && stqValid(stqPtr(i)))){
// stqValid(stqPtr(i)) := false.B
// }
// XSDebug("sptrtable: id %d ptr %d valid %d\n", i.U, stqPtr(i), stqValid(stqPtr(i)))
// }
// when(expRedirect){
// //invalidate uncommited store
// //FIXME
// }
//
// io.in.ready := io.out.fire()
//
// val validLoad = RegInit(false.B)
// when(state =/= s_idle && !io.in.valid) { validLoad := false.B }
// when(state === s_idle && io.in.valid && !retiringStore && dmem.req.fire()) { validLoad := true.B }
// io.out.valid := (!isStoreIn && !retiringStore && validLoad && Mux(partialLoad, state === s_partialLoad, dmem.resp.fire() && (state === s_wait_resp)) || stqEnqueue) && io.in.valid
// io.out.bits.uop <> io.in.bits.uop
// io.out.bits.data := Mux(partialLoad, rdataPartialLoad, rdata)
// // io.out.bits.debug.isMMIO := AddressSpace.isMMIO(addr) && io.out.valid
// io.out.bits.debug.isMMIO := AddressSpace.isMMIO(addr) //for debug
// io.out.bits.redirect := DontCare
// io.out.bits.redirectValid := false.B
//
// when(io.out.fire()){
// XSDebug("LSU fire: pc %x addr %x mmio %x isStoreIn %x retiringStore %x partialLoad %x dmem %x stqEnqueue %x state %x dmemres %x fwdres %x\n",
// io.in.bits.uop.cf.pc,
// addr,
// io.out.bits.debug.isMMIO,
// isStoreIn,
// retiringStore,
// partialLoad,
// dmem.resp.fire(),
// stqEnqueue,
// state,
// dmem.resp.bits.rdata,
// io.out.bits.data
// )
// }
//
// // debug
// XSDebug("state: %d (valid, ready): in (%d,%d) out (%d,%d)\n", state, io.in.valid, io.in.ready, io.out.valid, io.out.ready)
// XSDebug("stqinfo: stqValid.asUInt %b stqHead %d stqTail %d stqCommited %d emptySlot %d\n", stqValid.asUInt, stqHead, stqTail, stqCommited, emptySlot)
// XSDebug(retiringStore, "retiringStore now...\n")
// XSInfo(io.dmem.req.fire() && io.dmem.req.bits.cmd =/= SimpleBusCmd.write, "[DMEM LOAD REQ] addr 0x%x wdata 0x%x size %d\n", dmem.req.bits.addr, dmem.req.bits.wdata, dmem.req.bits.size)
// XSInfo(io.dmem.req.fire() && io.dmem.req.bits.cmd === SimpleBusCmd.write, "[DMEM STORE REQ] addr 0x%x wdata 0x%x size %d\n", dmem.req.bits.addr, dmem.req.bits.wdata, dmem.req.bits.size)
// XSInfo(io.dmem.resp.fire(), "[DMEM RESP] data %x\n", rdata)
//}
......@@ -3,7 +3,7 @@ package xiangshan.backend.exu
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
import utils._
import xiangshan.backend.MDUOpType
import xiangshan.backend.fu.FunctionUnit._
......@@ -18,7 +18,8 @@ class MulDivExeUnit extends Exu(Exu.mulDivExeUnitCfg){
val div = Module(new DivExeUnit)
for(x <- Seq(mul.io, div.io)){
x.scommit <> DontCare
x.mcommit <> DontCare
x.exception <> DontCare
x.dmem <> DontCare
x.in.bits := io.in.bits
x.redirect := io.redirect
......
此差异已折叠。
......@@ -3,7 +3,7 @@ package xiangshan.backend.fu
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
import utils._
import xiangshan.backend._
import xiangshan.backend.fu.FunctionUnit._
......@@ -22,6 +22,7 @@ class Divider(len: Int) extends FunctionUnit(divCfg) {
val (a, b) = (io.in.bits.src1, io.in.bits.src2)
val divBy0 = b === 0.U(len.W)
val divBy0Reg = RegEnable(divBy0, newReq)
val shiftReg = Reg(UInt((1 + len * 2).W))
val hi = shiftReg(len * 2, len)
......@@ -50,7 +51,7 @@ class Divider(len: Int) extends FunctionUnit(divCfg) {
// When divide by 0, the quotient should be all 1's.
// Therefore we can not shift in 0s here.
// We do not skip any shift to avoid this.
cnt.value := Mux(divBy0, 0.U, Mux(canSkipShift >= (len-1).U, (len-1).U, canSkipShift))
cnt.value := Mux(divBy0Reg, 0.U, Mux(canSkipShift >= (len-1).U, (len-1).U, canSkipShift))
state := s_shift
} .elsewhen (state === s_shift) {
shiftReg := aValx2Reg << cnt.value
......@@ -66,7 +67,7 @@ class Divider(len: Int) extends FunctionUnit(divCfg) {
}
}
when(state=/=s_idle && ctrlReg.uop.brTag.needFlush(io.redirect)){
when(state=/=s_idle && ctrlReg.uop.needFlush(io.redirect)){
state := s_idle
}
......
......@@ -3,7 +3,7 @@ package xiangshan.backend.fu
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
import utils._
import xiangshan.backend._
import xiangshan.backend.fu.FunctionUnit._
......
......@@ -3,7 +3,7 @@ package xiangshan.backend.fu
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
import utils._
import xiangshan.backend._
import xiangshan.backend.fu.FunctionUnit._
......
......@@ -3,7 +3,7 @@ package xiangshan.backend.fu
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
import utils._
import xiangshan.backend._
import xiangshan.backend.fu.FunctionUnit._
......
......@@ -3,7 +3,7 @@ package xiangshan.backend.fu
import chisel3._
import chisel3.util._
import xiangshan._
import xiangshan.utils._
import utils._
import xiangshan.backend._
import xiangshan.backend.fu.FunctionUnit._
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册