提交 a7006537 编写于 作者: Y Yinan Xu

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

#!/bin/bash
echo $1
echo $2
grep -rn $1 $2/src/main/scala/xiangshan
if [[ $? == 0 ]];
then
exit 1
fi
exit 0
......@@ -3,7 +3,7 @@ name: EMU Test
on:
push:
branches: [ master, update-ci ]
branches: [ master, update-ci]
pull_request:
branches: [ master ]
......@@ -15,30 +15,19 @@ jobs:
- uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: Check Wiring
run: bash .github/workflows/check-usage.sh "BoringUtils" $GITHUB_WORKSPACE
- name: Set env
run: |
echo ::set-env name=NEMU_HOME::/home/ci-runner/xsenv/NEMU
echo ::set-env name=NOOP_HOME::$GITHUB_WORKSPACE
echo "NEMU_HOME=/home/ci-runner/xsenv/NEMU" >> $GITHUB_ENV
echo "NOOP_HOME=$GITHUB_WORKSPACE" >> $GITHUB_ENV
echo "RVTEST_HOME=/home/ci-runner/xsenv/riscv-tests" >> $GITHUB_ENV
echo "AM_HOME=/home/ci-runner/xsenv/nexus-am" >> $GITHUB_ENV
- name: Build EMU
run:
make ./build/emu SIM_ARGS=--disable-log EMU_THREADS=16 NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME -j20
cputest:
runs-on: self-hosted
name: Run cputest
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
make ./build/emu SIM_ARGS=--disable-all NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME -j60
- name: Run cputest
run: |
echo $AM_HOME
echo $NEMU_HOME
echo $NOOP_HOME
CPU_TEST_DIR=$AM_HOME/tests/cputest
echo $CPU_TEST_DIR
ret=0
......@@ -54,38 +43,9 @@ jobs:
fi
done
exit $ret
microbench:
runs-on: self-hosted
name: Run microbench
needs: [build-emu]
steps:
- name: Set env
- name: Run riscv-tests
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
make -C $RVTEST_HOME/isa/ SUITES+=rv64ui SUITES+=rv64um SUITES+=rv64ua SUITES+=rv64uf SUITES+=rv64ud NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME noop_run 2> /dev/null
- 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 2> /dev/null
riscv-tests:
runs-on: self-hosted
name: Run riscv-tests
needs: [build-emu]
steps:
- name: Set env
run: |
echo ::set-env name=NEMU_HOME::/home/ci-runner/xsenv/NEMU
echo ::set-env name=NOOP_HOME::$GITHUB_WORKSPACE
echo ::set-env name=RVTEST_HOME::/home/ci-runner/xsenv/riscv-tests
- name: Run riscv-test
run: |
echo $NEMU_HOME
echo $NOOP_HOME
echo $RVTEST_HOME
make -C $RVTEST_HOME/isa/ SUITES+=rv64ui SUITES+=rv64um SUITES+=rv64ua NEMU_HOME=$NEMU_HOME NOOP_HOME=$NOOP_HOME noop_run 2> /dev/null
......@@ -342,8 +342,10 @@ hs_err_pid*
.vscode
.metals
.bloop
.bsp
.coursier
mill.rdiB
stale_outputs_checked
*.snapshot
[submodule "rocket-chip"]
path = rocket-chip
url = https://github.com/chipsalliance/rocket-chip.git
branch = d6bd3c61993637c3f10544c59e861fae8af29f39
url = https://github.com/RISCVERS/rocket-chip.git
branch = 147bdcc4a26c74e5d7a47e3d667d456699d6d11f
[submodule "block-inclusivecache-sifive"]
path = block-inclusivecache-sifive
url = https://github.com/RISCVERS/block-inclusivecache-sifive.git
......@@ -10,3 +10,9 @@
path = chiseltest
url = https://github.com/ucb-bar/chisel-testers2.git
branch = 3e3ecc5b25b7b6bc48341ec07c7a54b7ad53bcb7
[submodule "api-config-chipsalliance"]
path = api-config-chipsalliance
url = https://github.com/chipsalliance/api-config-chipsalliance
[submodule "berkeley-hardfloat"]
path = berkeley-hardfloat
url = https://github.com/ucb-bar/berkeley-hardfloat
......@@ -9,6 +9,14 @@ MEM_GEN = ./scripts/vlsi_mem_gen
SIMTOP = top.TestMain
IMAGE ?= temp
# co-simulation with DRAMsim3
ifeq ($(WITH_DRAMSIM3),1)
ifndef DRAMSIM3_HOME
$(error DRAMSIM3_HOME is not set)
endif
override SIM_ARGS += --with-dramsim3
endif
# remote machine with more cores to speedup c++ build
REMOTE ?= localhost
......@@ -19,16 +27,17 @@ help:
$(TOP_V): $(SCALA_FILE)
mkdir -p $(@D)
mill XiangShan.runMain top.$(TOP) -X verilog -td $(@D) --output-file $(@F) --infer-rw $(FPGATOP) --repl-seq-mem -c:$(FPGATOP):-o:$(@D)/$(@F).conf
$(MEM_GEN) $(@D)/$(@F).conf >> $@
sed -i -e 's/_\(aw\|ar\|w\|r\|b\)_\(\|bits_\)/_\1/g' $@
@git log -n 1 >> .__head__
@git diff >> .__diff__
@sed -i 's/^/\/\// ' .__head__
@sed -i 's/^/\/\//' .__diff__
@cat .__head__ .__diff__ $@ > .__out__
@mv .__out__ $@
@rm .__head__ .__diff__
mill XiangShan.test.runMain $(SIMTOP) -X verilog -td $(@D) --full-stacktrace --output-file $(@F) --disable-all --fpga-platform --remove-assert $(SIM_ARGS)
# mill XiangShan.runMain top.$(TOP) -X verilog -td $(@D) --output-file $(@F) --infer-rw $(FPGATOP) --repl-seq-mem -c:$(FPGATOP):-o:$(@D)/$(@F).conf
# $(MEM_GEN) $(@D)/$(@F).conf >> $@
# sed -i -e 's/_\(aw\|ar\|w\|r\|b\)_\(\|bits_\)/_\1/g' $@
# @git log -n 1 >> .__head__
# @git diff >> .__diff__
# @sed -i 's/^/\/\// ' .__head__
# @sed -i 's/^/\/\//' .__diff__
# @cat .__head__ .__diff__ $@ > .__out__
# @mv .__out__ $@
# @rm .__head__ .__diff__
deploy: build/top.zip
......@@ -40,68 +49,98 @@ build/top.zip: $(TOP_V)
verilog: $(TOP_V)
SIM_TOP = XSSimTop
SIM_TOP = XSSimTop
SIM_TOP_V = $(BUILD_DIR)/$(SIM_TOP).v
SIM_ARGS =
$(SIM_TOP_V): $(SCALA_FILE) $(TEST_FILE)
mkdir -p $(@D)
date -R
mill XiangShan.test.runMain $(SIMTOP) -X verilog -td $(@D) --full-stacktrace --output-file $(@F) $(SIM_ARGS)
sed -i '/module XSSimTop/,/endmodule/d' $(SIM_TOP_V)
sed -i -e 's/$$fatal/$$finish/g' $(SIM_TOP_V)
date -R
EMU_TOP = XSSimSoC
EMU_CSRC_DIR = $(abspath ./src/test/csrc)
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_VFILES = $(shell find $(EMU_VSRC_DIR) -name "*.v" -or -name "*.sv")
EMU_CXXFLAGS = -std=c++11 -static -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
EMU_THREADS = 1
ifeq ($(EMU_THREADS), 1)
VTHREAD_FLAGS =
else
VTHREAD_FLAGS = --threads $(EMU_THREADS) --threads-dpi none
EMU_LDFLAGS += -lpthread -lSDL2 -ldl -lz
VEXTRA_FLAGS = -I$(abspath $(BUILD_DIR)) --x-assign unique -O3 -CFLAGS "$(EMU_CXXFLAGS)" -LDFLAGS "$(EMU_LDFLAGS)"
# Verilator trace support
EMU_TRACE ?=
ifeq ($(EMU_TRACE),1)
VEXTRA_FLAGS += --trace
endif
# Verilator multi-thread support
EMU_THREADS ?= 1
ifneq ($(EMU_THREADS),1)
VEXTRA_FLAGS += --threads $(EMU_THREADS) --threads-dpi none
endif
# Verilator savable
EMU_SNAPSHOT ?=
ifeq ($(EMU_SNAPSHOT),1)
VEXTRA_FLAGS += --savable
EMU_CXXFLAGS += -DVM_SAVABLE
endif
# co-simulation with DRAMsim3
ifeq ($(WITH_DRAMSIM3),1)
EMU_CXXFLAGS += -I$(DRAMSIM3_HOME)/src
EMU_CXXFLAGS += -DWITH_DRAMSIM3 -DDRAMSIM3_CONFIG=\\\"$(DRAMSIM3_HOME)/configs/XiangShan.ini\\\" -DDRAMSIM3_OUTDIR=\\\"$(BUILD_DIR)\\\"
EMU_LDFLAGS += $(DRAMSIM3_HOME)/build/libdramsim3.a
endif
# --trace
VERILATOR_FLAGS = --top-module $(SIM_TOP) \
VERILATOR_FLAGS = --top-module $(EMU_TOP) \
+define+VERILATOR=1 \
+define+PRINTF_COND=1 \
+define+RANDOMIZE_REG_INIT \
+define+RANDOMIZE_MEM_INIT \
$(VTHREAD_FLAGS) \
$(VEXTRA_FLAGS) \
--assert \
--trace \
--savable \
--stats-vars \
--output-split 5000 \
--output-split-cfuncs 5000 \
-I$(abspath $(BUILD_DIR)) \
--x-assign unique -O3 -CFLAGS "$(EMU_CXXFLAGS)" \
-LDFLAGS "$(EMU_LDFLAGS)"
--output-split-cfuncs 5000
EMU_MK := $(BUILD_DIR)/emu-compile/V$(SIM_TOP).mk
EMU_MK := $(BUILD_DIR)/emu-compile/V$(EMU_TOP).mk
EMU_DEPS := $(EMU_VFILES) $(EMU_CXXFILES)
EMU_HEADERS := $(shell find $(EMU_CSRC_DIR) -name "*.h")
EMU := $(BUILD_DIR)/emu
$(EMU_MK): $(SIM_TOP_V) | $(EMU_DEPS)
@mkdir -p $(@D)
date -R
verilator --cc --exe $(VERILATOR_FLAGS) \
-o $(abspath $(EMU)) -Mdir $(@D) $^ $(EMU_DEPS)
date -R
ifndef NEMU_HOME
$(error NEMU_HOME is not set)
endif
REF_SO := $(NEMU_HOME)/build/riscv64-nemu-interpreter-so
$(REF_SO):
$(MAKE) -C $(NEMU_HOME) ISA=riscv64 SHARE=1
$(EMU): $(EMU_MK) $(EMU_DEPS) $(EMU_HEADERS) $(REF_SO)
date -R
ifeq ($(REMOTE),localhost)
CPPFLAGS=-DREF_SO=\\\"$(REF_SO)\\\" $(MAKE) VM_PARALLEL_BUILDS=1 OPT_FAST="-O3" -C $(abspath $(dir $(EMU_MK))) -f $(abspath $(EMU_MK))
else
ssh -tt $(REMOTE) 'CPPFLAGS=-DREF_SO=\\\"$(REF_SO)\\\" $(MAKE) -j80 VM_PARALLEL_BUILDS=1 OPT_FAST="-O3" -C $(abspath $(dir $(EMU_MK))) -f $(abspath $(EMU_MK))'
ssh -tt $(REMOTE) 'CPPFLAGS=-DREF_SO=\\\"$(REF_SO)\\\" $(MAKE) -j128 VM_PARALLEL_BUILDS=1 OPT_FAST="-O3" -C $(abspath $(dir $(EMU_MK))) -f $(abspath $(EMU_MK))'
endif
date -R
SEED ?= $(shell shuf -i 1-10000 -n 1)
VME_SOURCE ?= $(shell pwd)
VME_MODULE ?=
# log will only be printed when (B<=GTimer<=E) && (L < loglevel)
# use 'emu -h' to see more details
......@@ -119,21 +158,46 @@ else
SNAPSHOT_OPTION = --load-snapshot=$(SNAPSHOT)
endif
ifndef NOOP_HOME
$(error NOOP_HOME is not set)
endif
EMU_FLAGS = -s $(SEED) -b $(B) -e $(E) $(SNAPSHOT_OPTION) $(WAVEFORM)
emu: $(EMU)
ls build
$(EMU) -i $(IMAGE) $(EMU_FLAGS)
# extract verilog module from sim_top.v
# usage: make vme VME_MODULE=Roq
vme: $(SIM_TOP_V)
mill XiangShan.runMain utils.ExtractVerilogModules -m $(VME_MODULE)
# usage: make phy_evaluate VME_MODULE=Roq REMOTE=100
phy_evaluate: vme
scp -r ./build/extracted/* $(REMOTE):~/phy_evaluation/remote_run/rtl
ssh -tt $(REMOTE) 'cd ~/phy_evaluation/remote_run && $(MAKE) evaluate DESIGN_NAME=$(VME_MODULE)'
scp -r $(REMOTE):~/phy_evaluation/remote_run/rpts ./build
# usage: make phy_evaluate_atc VME_MODULE=Roq REMOTE=100
phy_evaluate_atc: vme
scp -r ./build/extracted/* $(REMOTE):~/phy_evaluation/remote_run/rtl
ssh -tt $(REMOTE) 'cd ~/phy_evaluation/remote_run && $(MAKE) evaluate_atc DESIGN_NAME=$(VME_MODULE)'
scp -r $(REMOTE):~/phy_evaluation/remote_run/rpts ./build
cache:
$(MAKE) emu IMAGE=Makefile
clean:
rm -rf $(BUILD_DIR)
git submodule foreach git clean -fdx
git clean -fd
rm -rf ./build
init:
git submodule update --init
@# do not use a recursive init to pull some not used submodules
cd ./rocket-chip/ && git submodule update --init api-config-chipsalliance hardfloat
.PHONY: verilog emu clean help init $(REF_SO)
bump:
git submodule foreach "git fetch origin&&git checkout master&&git reset --hard origin/master"
bsp:
mill -i mill.contrib.BSP/install
.PHONY: verilog emu clean help init bump bsp $(REF_SO)
Subproject commit fd8df1105a92065425cd353b6855777e35bd79b4
Subproject commit 267357bdae5973a30565da6ebc728d513827ca5e
Subproject commit 5ca43398ac8b1b293291bd4e6e8c233be6c66968
Subproject commit 3d6bdf10d7b740588130e3056c8fd29f4175cadb
import os.Path
import mill._
import mill.modules.Util
import $ivy.`com.lihaoyi::mill-contrib-buildinfo:$MILL_VERSION`
import $ivy.`com.lihaoyi::mill-contrib-bsp:$MILL_VERSION`
import mill.contrib.buildinfo.BuildInfo
import scalalib._
import coursier.maven.MavenRepository
......@@ -29,6 +32,15 @@ val chisel = Agg(
ivy"edu.berkeley.cs::chisel3:3.4.0"
)
object `api-config-chipsalliance` extends CommonModule {
override def millSourcePath = super.millSourcePath / "design" / "craft"
}
object hardfloat extends SbtModule with CommonModule {
override def millSourcePath = os.pwd / "berkeley-hardfloat"
override def ivyDeps = super.ivyDeps() ++ chisel
}
object `rocket-chip` extends SbtModule with CommonModule {
override def ivyDeps = super.ivyDeps() ++ Agg(
......@@ -36,17 +48,8 @@ object `rocket-chip` extends SbtModule with CommonModule {
ivy"org.json4s::json4s-jackson:3.6.1"
) ++ chisel
object `api-config-chipsalliance` extends CommonModule {
override def millSourcePath = super.millSourcePath / 'design / 'craft
}
object macros extends SbtModule with CommonModule
object hardfloat extends SbtModule with CommonModule {
override def ivyDeps = super.ivyDeps() ++ chisel
}
override def moduleDeps = super.moduleDeps ++ Seq(
`api-config-chipsalliance`, macros, hardfloat
)
......@@ -63,13 +66,13 @@ object `block-inclusivecache-sifive` extends CommonModule {
object chiseltest extends CommonModule with SbtModule {
override def ivyDeps = super.ivyDeps() ++ Agg(
ivy"edu.berkeley.cs::treadle:1.3.0",
ivy"org.scalatest::scalatest:3.0.8",
ivy"com.lihaoyi::utest:0.7.4"
ivy"edu.berkeley.cs::treadle:1.3.0",
ivy"org.scalatest::scalatest:3.2.0",
ivy"com.lihaoyi::utest:0.7.4"
) ++ chisel
object test extends Tests {
def ivyDeps = Agg(ivy"org.scalacheck::scalacheck:1.14.3")
def testFrameworks = Seq("org.scalatest.tools.Framework")
def ivyDeps = Agg(ivy"org.scalacheck::scalacheck:1.14.3")
def testFrameworks = Seq("org.scalatest.tools.Framework")
}
}
......@@ -81,15 +84,14 @@ object XiangShan extends CommonModule with SbtModule {
override def ivyDeps = super.ivyDeps() ++ chisel
override def moduleDeps = super.moduleDeps ++ Seq(
`rocket-chip`,
`block-inclusivecache-sifive`,
chiseltest
`rocket-chip`,
`block-inclusivecache-sifive`,
chiseltest
)
object test extends Tests {
override def ivyDeps = super.ivyDeps() ++ Agg(
ivy"org.scalatest::scalatest:3.0.4",
ivy"edu.berkeley.cs::chisel-iotesters:1.2+",
ivy"org.scalatest::scalatest:3.2.0"
)
def testFrameworks = Seq(
......@@ -101,5 +103,4 @@ object XiangShan extends CommonModule with SbtModule {
}
}
}
}
\ No newline at end of file
Subproject commit 3e3ecc5b25b7b6bc48341ec07c7a54b7ad53bcb7
Subproject commit 6a2e1776c91635deb7e1982b2333611ae620e777
......@@ -4,7 +4,7 @@ SINGLETEST = ALL=min3
B ?= 0
E ?= 0
V ?= ALL
V ?= OFF
#V ?= OFF
EMU_ARGS = B=$(B) E=$(E) V=$(V)
......@@ -13,7 +13,8 @@ EMU_ARGS = B=$(B) E=$(E) V=$(V)
# ------------------------------------------------------------------
cache:
$(MAKE) -C $(AM_HOME)/tests/cachetest $(ARCH) ALL=loader $(EMU_ARGS) run 2>&1 | tee > loader.log
$(MAKE) -C $(AM_HOME)/tests/cachetest $(ARCH) ALL=loader $(EMU_ARGS) run
#2>&1 | tee > loader.log
#2>&1 | tee > loader.log
cpu:
......@@ -40,6 +41,7 @@ amtest:
microbench:
$(MAKE) -C $(AM_HOME)/apps/microbench $(ARCH) $(EMU_ARGS) mainargs=test run
#2>&1 | tee > microbench.log
#2 > microbench.log
cat microbench.log | grep IPC
......@@ -48,7 +50,7 @@ microbench_train:
cat microbench.log | grep IPC
coremark:
$(MAKE) -C $(AM_HOME)/apps/coremark $(ARCH) $(EMU_ARGS) mainargs=test run
$(MAKE) -C $(AM_HOME)/apps/coremark $(ARCH) $(EMU_ARGS) mainargs=test run
#2 > coremark.log
cat coremark.log | grep IPC
......
......@@ -6,7 +6,7 @@ for test in $(ls $TEST_HOME/tests)
do
t=${test%.c}
echo -n -e "\x1b[0m $t: "
make -C $TEST_HOME ARCH=riscv64-noop E=0 ALL=$t run 2>/dev/null | grep "HIT GOOD TRAP"
make -C $TEST_HOME ARCH=riscv64-noop E=0 ALL=$t run 2>/dev/null | grep -E "HIT GOOD TRAP|IPC"
if [[ $? == 1 ]];
then
echo -e "\x1b[31mfail"
......
#!/bin/bash
log_dir=$1
tage_w_sc_w=$(grep "scUpdate" $log_dir | grep "sc(1), tage(1)" -c)
tage_w_sc_r=$(grep "scUpdate" $log_dir | grep "sc(0), tage(1)" -c)
tage_r_sc_w=$(grep "scUpdate" $log_dir | grep "sc(1), tage(0)" -c)
tage_r_sc_r=$(grep "scUpdate" $log_dir | grep "sc(0), tage(0)" -c)
echo $tage_r_sc_w tage right but mispredicted by sc
echo $tage_w_sc_r tage wrong and rectified by sc
echo `expr $tage_w_sc_w + $tage_r_sc_r` branches remain unchanged, in which $tage_w_sc_w are wrong
Subproject commit d6bd3c61993637c3f10544c59e861fae8af29f39
Subproject commit 147bdcc4a26c74e5d7a47e3d667d456699d6d11f
此差异已折叠。
/**************************************************************************************
* 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._
import chisel3.util._
import utils._
class SimpleBusCrossbar1toN(addressSpace: List[(Long, Long)]) extends Module {
val io = IO(new Bundle {
val in = Flipped(new SimpleBusUC)
val out = Vec(addressSpace.length, new SimpleBusUC)
})
val s_idle :: s_resp :: s_error :: Nil = Enum(3)
val state = RegInit(s_idle)
// select the output channel according to the address
val addr = io.in.req.bits.addr
val outSelVec = VecInit(addressSpace.map(
range => (addr >= range._1.U && addr < (range._1 + range._2).U)))
val outSelIdx = PriorityEncoder(outSelVec)
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
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
(io.out zip outSelVec).map { case (o, v) => {
o.req.bits := io.in.req.bits
o.req.valid := v && (io.in.req.valid && (state === s_idle))
o.resp.ready := v
}}
switch (state) {
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() || 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 || reqInvalidAddr
Debug() {
when (state === s_idle && io.in.req.valid) {
printf(p"${GTimer()}: xbar: in.req: ${io.in.req.bits}\n")
}
when (outSel.req.fire()) {
printf(p"${GTimer()}: xbar: outSelIdx = ${outSelIdx}, outSel.req: ${outSel.req.bits}\n")
}
when (outSel.resp.fire()) {
printf(p"${GTimer()}: xbar: outSelIdx= ${outSelIdx}, outSel.resp: ${outSel.resp.bits}\n")
}
when (io.in.resp.fire()) {
printf(p"${GTimer()}: xbar: in.resp: ${io.in.resp.bits}\n")
}
}
}
class SimpleBusCrossbarNto1(n: Int, userBits:Int = 0) extends Module {
val io = IO(new Bundle {
val in = Flipped(Vec(n, new SimpleBusUC(userBits)))
val out = new SimpleBusUC(userBits)
})
val s_idle :: s_readResp :: s_writeResp :: Nil = Enum(3)
val state = RegInit(s_idle)
val lockWriteFun = ((x: SimpleBusReqBundle) => x.isWrite() && x.isBurst())
val inputArb = Module(new LockingArbiter(chiselTypeOf(io.in(0).req.bits), n, 8, Some(lockWriteFun)))
(inputArb.io.in zip io.in.map(_.req)).map{ case (arb, in) => arb <> in }
val thisReq = inputArb.io.out
assert(!(thisReq.valid && !thisReq.bits.isRead() && !thisReq.bits.isWrite()))
val inflightSrc = Reg(UInt(log2Up(n).W))
io.out.req.bits := thisReq.bits
// bind correct valid and ready signals
io.out.req.valid := thisReq.valid && (state === s_idle)
thisReq.ready := io.out.req.ready && (state === s_idle)
io.in.map(_.resp.bits := io.out.resp.bits)
io.in.map(_.resp.valid := false.B)
(io.in(inflightSrc).resp, io.out.resp) match { case (l, r) => {
l.valid := r.valid
r.ready := l.ready
}}
switch (state) {
is (s_idle) {
when (thisReq.fire()) {
inflightSrc := inputArb.io.chosen
when (thisReq.bits.isRead()) { state := s_readResp }
.elsewhen (thisReq.bits.isWriteLast() || thisReq.bits.isWriteSingle()) { state := s_writeResp }
}
}
is (s_readResp) { when (io.out.resp.fire() && io.out.resp.bits.isReadLast()) { state := s_idle } }
is (s_writeResp) { when (io.out.resp.fire()) { state := s_idle } }
}
}
class SimpleBusCrossbar(n: Int, addressSpace: List[(Long, Long)]) extends Module {
val io = IO(new Bundle {
val in = Flipped(Vec(n, new SimpleBusUC))
val out = Vec(addressSpace.length, new SimpleBusUC)
})
val inXbar = Module(new SimpleBusCrossbarNto1(n))
val outXbar = Module(new SimpleBusCrossbar1toN(addressSpace))
inXbar.io.in <> io.in
outXbar.io.in <> inXbar.io.out
io.out <> outXbar.io.out
}
package bus.simplebus
import chisel3._
import chisel3.util._
import chisel3.util.experimental.loadMemoryFromFile
import noop.HasNOOPParameter
class DistributedMem(memByte: Int, dualPort: Boolean, delayCycles: Int = 0, dataFile: String = "")
extends Module with HasNOOPParameter {
val io = IO(new Bundle {
val rw = Flipped(new SimpleBusUC)
val ro = Flipped(new SimpleBusUC)
})
val wordNum = memByte / 8
val nBank = XLEN / 8
val memAddrBits = log2Up(wordNum)
def Index(addr: UInt): UInt = addr(memAddrBits + 2 - 1, 2)
val rwIdx = Index(io.rw.req.bits.addr)
val roIdx = Index(io.ro.req.bits.addr)
val wen = io.rw.isWrite()
val wdataVec = VecInit.tabulate(nBank) { i => io.rw.req.bits.wdata(8 * (i + 1) - 1, 8 * i) }
val wmask = VecInit.tabulate(nBank) { i => io.rw.req.bits.wmask(i).asBool() }
val rwData = Wire(UInt(XLEN.W))
val roData = Wire(UInt(XLEN.W))
val mem = Mem(wordNum, Vec(nBank, UInt(8.W)))
if (dataFile != "")
loadMemoryFromFile(mem, dataFile)
rwData := Cat(mem.read(rwIdx).reverse)
roData := Cat(mem.read(roIdx).reverse)
when (wen) { mem.write(rwIdx, wdataVec, wmask) }
def readPort(p: SimpleBusUC, rdata: UInt) = {
val s_idle :: s_reading :: Nil = Enum(2)
val state = RegInit(s_idle)
switch (state) {
is (s_idle) {
when (p.req.fire()) { state := Mux(p.resp.fire(), s_idle, s_reading) }
}
is (s_reading) {
when (p.resp.fire()) { state := s_idle }
}
}
p.req.ready := state === s_idle
p.resp.bits.rdata := rdata
p.resp.valid := (if (delayCycles == 0) p.req.fire() else Counter(state === s_reading, delayCycles)._2)
}
readPort(io.rw, rwData)
if (dualPort) {
readPort(io.ro, roData)
}
else {
io.ro := DontCare
}
}
package bus.simplebus
import chisel3._
import chisel3.util._
import noop.HasNOOPParameter
import utils._
import bus.axi4._
sealed abstract class SimpleBusBundle extends Bundle with HasNOOPParameter
object SimpleBusCmd {
// req
// hit | miss
def read = "b0000".U // read | refill
def write = "b0001".U // write | refill
def readBurst = "b0010".U // read | refill
def writeBurst = "b0011".U // write | refill
def writeLast = "b0111".U // write | refill
def probe = "b1000".U // read | do nothing
def prefetch = "b0100".U // read | refill
// resp
def readLast = "b0110".U
def writeResp = "b0101".U
def probeHit = "b1100".U
def probeMiss = "b1000".U
def apply() = UInt(4.W)
}
class SimpleBusReqBundle(val userBits: Int = 0, val addrBits: Int = 32) extends SimpleBusBundle {
val addr = Output(UInt(addrBits.W))
val size = Output(UInt(3.W))
val cmd = Output(SimpleBusCmd())
val wmask = Output(UInt((DataBits / 8).W))
val wdata = Output(UInt(DataBits.W))
val user = if (userBits > 0) Some(Output(UInt(userBits.W))) else None
override def toPrintable: Printable = {
p"addr = 0x${Hexadecimal(addr)}, cmd = ${cmd}, size = ${size}, " +
p"wmask = 0x${Hexadecimal(wmask)}, wdata = 0x${Hexadecimal(wdata)}"
}
def apply(addr: UInt, cmd: UInt, size: UInt, wdata: UInt, wmask: UInt, user: UInt = 0.U) {
this.addr := addr
this.cmd := cmd
this.size := size
this.wdata := wdata
this.wmask := wmask
this.user.map(_ := user)
}
def isRead() = !cmd(0) && !cmd(3)
def isWrite() = cmd(0)
def isBurst() = cmd(1)
def isReadBurst() = cmd === SimpleBusCmd.readBurst
def isWriteSingle() = cmd === SimpleBusCmd.write
def isWriteLast() = cmd === SimpleBusCmd.writeLast
def isProbe() = cmd === SimpleBusCmd.probe
def isPrefetch() = cmd === SimpleBusCmd.prefetch
}
class SimpleBusRespBundle(val userBits: Int = 0) extends SimpleBusBundle {
val cmd = Output(SimpleBusCmd())
val rdata = Output(UInt(DataBits.W))
val user = if (userBits > 0) Some(Output(UInt(userBits.W))) else None
override def toPrintable: Printable = p"rdata = ${Hexadecimal(rdata)}, cmd = ${cmd}"
def isReadLast() = cmd === SimpleBusCmd.readLast
def isProbeHit() = cmd === SimpleBusCmd.probeHit
def isProbeMiss() = cmd === SimpleBusCmd.probeMiss
def isWriteResp() = cmd === SimpleBusCmd.writeResp
def isPrefetch() = cmd === SimpleBusCmd.prefetch
}
// Uncache
class SimpleBusUC(val userBits: Int = 0, val addrBits: Int = 32) extends SimpleBusBundle {
val req = Decoupled(new SimpleBusReqBundle(userBits, addrBits))
val resp = Flipped(Decoupled(new SimpleBusRespBundle(userBits)))
def isWrite() = req.valid && req.bits.isWrite()
def isRead() = req.valid && req.bits.isRead()
def toAXI4Lite() = SimpleBus2AXI4Converter(this, new AXI4Lite)
def toAXI4() = SimpleBus2AXI4Converter(this, new AXI4)
def dump(name: String) = {
when (req.fire()) { printf(p"${GTimer()},[${name}] ${req.bits}\n") }
when (resp.fire()) { printf(p"${GTimer()},[${name}] ${resp.bits}\n") }
}
}
// Cache
class SimpleBusC(val userBits: Int = 0) extends SimpleBusBundle {
val mem = new SimpleBusUC(userBits)
val coh = Flipped(new SimpleBusUC(userBits))
def memtoAXI4() = this.mem.toAXI4
}
package bus.simplebus
import chisel3._
import chisel3.util._
import bus.axi4._
import utils._
class AXI42SimpleBusConverter() extends Module {
val io = IO(new Bundle {
val in = Flipped(new AXI4(idBits = 18))
val out = new SimpleBusUC()
})
val (axi, mem) = (io.in, io.out)
val (ar, aw, w, r, b) = (axi.ar.bits, axi.aw.bits, axi.w.bits, axi.r.bits, axi.b.bits)
val (req, resp) = (mem.req.bits, mem.resp.bits)
// Default value
val inflight_id_reg = RegInit(0.U)
val axi_na :: axi_read :: axi_write :: Nil = Enum(3)
val inflight_type = RegInit(axi_na)
private def setState(axi_type: UInt, id: UInt) = {
inflight_id_reg := id
inflight_type := axi_type;
}
private def resetState() = {
inflight_type := axi_na
inflight_id_reg := 0.U
}
private def is_inflight() = {
inflight_type =/= axi_na
}
// Default
val default_mem = 0.U.asTypeOf(new SimpleBusUC)
val default_axi = 0.U.asTypeOf(new AXI4)
req := default_mem.req.bits
r := default_axi.r.bits
b := default_axi.b.bits
// Read Path
when (axi.ar.valid) {
mem.req.valid := true.B
req.addr := ar.addr
req.cmd := Mux(ar.len === 0.U, SimpleBusCmd.read, SimpleBusCmd.readBurst)
// TODO: consider ar.burst
req.size := ar.size
req.user.foreach(_ := ar.user)
req.wmask := 0.U
req.wdata := 0.U
when (mem.req.fire) {
setState(axi_read, ar.id)
}
}
when (mem.resp.valid) {
axi.r.valid := true.B
r.data := resp.rdata
r.id := inflight_id_reg
// TODO: r.resp handling
r.resp := AXI4Parameters.RESP_OKAY
r.last := resp.isReadLast
resp.user.foreach(r.user := _)
when (axi.r.fire && resp.isReadLast) {
resetState()
}
}
// Write Path
val aw_reg = Reg(new AXI4BundleA(AXI4Parameters.idBits))
val bresp_en = RegInit(false.B)
when (axi.aw.valid && !axi.ar.valid) {
aw_reg := aw
when (axi.aw.fire) {
setState(axi_write, aw.id)
}
}
when (axi.w.valid) {
mem.req.valid := true.B
req.cmd := Mux(aw_reg.len === 0.U, SimpleBusCmd.write,
Mux(w.last, SimpleBusCmd.writeLast, SimpleBusCmd.writeBurst))
req.addr := aw_reg.addr
req.size := aw_reg.size
req.wmask := w.strb
req.wdata := w.data
req.user.foreach(_ := aw.user)
when (axi.w.fire && w.last) {
bresp_en := true.B
}
}
when (axi.b.fire) {
bresp_en := false.B
resetState()
}
// Arbitration
// Slave's ready maybe generated according to valid signal, so let valid signals go through.
mem.req.valid := axi.ar.valid || axi.w.valid
mem.resp.ready := true.B || (inflight_type === axi_read && axi.r.ready) || (inflight_type === axi_write && axi.b.ready)
axi.ar.ready := !is_inflight && mem.req.ready
axi.r.valid := inflight_type === axi_read && mem.resp.valid
// AW should be buffered so no ready is considered.
axi.aw.ready := !is_inflight && !axi.ar.valid
axi.w.ready := inflight_type === axi_write && mem.req.ready
axi.b.valid := bresp_en && mem.resp.valid
axi.b.bits.resp := AXI4Parameters.RESP_OKAY
}
class SimpleBus2AXI4Converter[OT <: AXI4Lite](outType: OT) extends Module {
val io = IO(new Bundle {
val in = Flipped(new SimpleBusUC)
val out = Flipped(Flipped(outType))
})
val toAXI4Lite = !(io.in.req.valid && io.in.req.bits.isBurst()) && (outType.getClass == classOf[AXI4Lite]).B
val toAXI4 = (outType.getClass == classOf[AXI4]).B
assert(toAXI4Lite || toAXI4)
val (mem, axi) = (io.in, io.out)
val (ar, aw, w, r, b) = (axi.ar.bits, axi.aw.bits, axi.w.bits, axi.r.bits, axi.b.bits)
ar.addr := mem.req.bits.addr
ar.prot := AXI4Parameters.PROT_PRIVILEDGED
w.data := mem.req.bits.wdata
w.strb := mem.req.bits.wmask
def LineBeats = 8
val wlast = WireInit(true.B)
val rlast = WireInit(true.B)
if (outType.getClass == classOf[AXI4]) {
val axi4 = io.out.asInstanceOf[AXI4]
axi4.ar.bits.id := 0.U
axi4.ar.bits.len := Mux(mem.req.bits.isBurst(), (LineBeats - 1).U, 0.U)
axi4.ar.bits.size := mem.req.bits.size
axi4.ar.bits.burst := AXI4Parameters.BURST_WRAP
axi4.ar.bits.lock := false.B
axi4.ar.bits.cache := 0.U
axi4.ar.bits.qos := 0.U
axi4.ar.bits.user := 0.U
axi4.w.bits.last := mem.req.bits.isWriteLast() || mem.req.bits.isWriteSingle()
wlast := axi4.w.bits.last
rlast := axi4.r.bits.last
}
aw := ar
mem.resp.bits.rdata := r.data
mem.resp.bits.cmd := Mux(rlast, SimpleBusCmd.readLast, 0.U)
val wSend = Wire(Bool())
val awAck = BoolStopWatch(axi.aw.fire(), wSend)
val wAck = BoolStopWatch(axi.w.fire() && wlast, wSend)
wSend := (axi.aw.fire() && axi.w.fire() && wlast) || (awAck && wAck)
val wen = RegEnable(mem.req.bits.isWrite(), mem.req.fire())
axi.ar.valid := mem.isRead()
axi.aw.valid := mem.isWrite() && !awAck
axi.w .valid := mem.isWrite() && !wAck
mem.req.ready := Mux(mem.req.bits.isWrite(), !wAck && axi.w.ready, axi.ar.ready)
axi.r.ready := mem.resp.ready
axi.b.ready := mem.resp.ready
mem.resp.valid := Mux(wen, axi.b.valid, axi.r.valid)
}
object SimpleBus2AXI4Converter {
def apply[OT <: AXI4Lite](in: SimpleBusUC, outType: OT): OT = {
val bridge = Module(new SimpleBus2AXI4Converter(outType))
bridge.io.in <> in
bridge.io.out
}
}
package bus.tilelink
import chisel3._
import chisel3.util._
import utils.{Debug, GTimer}
// Only support A and D channel, very naive...
class NaiveTL1toN
(
addressSpace: List[(Long, Long)],
para: TLParameters
) extends Module{
val io = IO(new Bundle() {
val in = Flipped(TLCached(para))
val out = Vec(addressSpace.length, TLCached(para))
})
io.in <> DontCare
io.out <> DontCare
val s_idle :: s_resp :: s_error :: Nil = Enum(3)
val state = RegInit(s_idle)
// select the output channel according to the address
val addr = io.in.a.bits.address
val outSelVec = VecInit(addressSpace.map(
range => addr >= range._1.U && addr < (range._1 + range._2).U
))
val outSelIdx = PriorityEncoder(outSelVec)
val outSel = io.out(outSelIdx)
val outSelIdxResp = RegEnable(outSelIdx, outSel.a.fire() && (state === s_idle))
val outSelResp = io.out(outSelIdxResp)
val reqInvalidAddr = io.in.a.valid && !outSelVec.asUInt.orR
when(
!(!io.in.a.valid || outSelVec.asUInt.orR) || (io.in.a.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.a.valid && outSelVec.asUInt.andR),
"address decode error, bad addr = 0x%x\n", addr
)
// bind out.req channel
(io.out zip outSelVec).foreach { case (o, v) =>
o.a.bits := io.in.a.bits
o.a.valid := v && (io.in.a.valid && (state === s_idle))
o.d.ready := v
}
switch (state) {
is (s_idle) {
when (outSel.a.fire()) { state := s_resp }
when (reqInvalidAddr) { state := s_error }
}
is (s_resp) { when (outSelResp.d.fire()) { state := s_idle } }
is (s_error) { when(io.in.d.fire()){ state := s_idle } }
}
io.in.d.valid := outSelResp.d.fire() || state === s_error
io.in.d.bits <> outSelResp.d.bits
// io.in.resp.bits.exc.get := state === s_error
outSelResp.d.ready := io.in.d.ready
io.in.a.ready := outSel.a.ready || reqInvalidAddr
Debug() {
when (state === s_idle && io.in.a.valid) {
printf(p"${GTimer()}: req: ")
io.in.a.bits.dump()
}
when (outSel.a.fire()) {
printf(p"${GTimer()}: xbar: outSelIdx = $outSelIdx, outSel.req: ")
outSel.a.bits.dump()
}
when (outSel.d.fire()) {
printf(p"${GTimer()}: xbar: outSelIdx= $outSelIdx, outSel.resp: ")
outSel.d.bits.dump()
}
when (io.in.d.fire()) {
printf(p"${GTimer()}: xbar: in.resp: ")
io.in.d.bits.dump()
}
}
}
......@@ -53,7 +53,7 @@ class SDHelper extends BlackBox with HasBlackBoxInline {
class AXI4DummySD
(
address: AddressSet
address: Seq[AddressSet]
)(implicit p: Parameters)
extends AXI4SlaveModule(address, executable = false) with HasSDConst
{
......
......@@ -8,7 +8,7 @@ import utils._
class AXI4Flash
(
address: AddressSet
address: Seq[AddressSet]
)(implicit p: Parameters)
extends AXI4SlaveModule(address, executable = false)
{
......
......@@ -14,7 +14,7 @@ class KeyboardIO extends Bundle {
// this Module is not tested
class AXI4Keyboard
(
address: AddressSet
address: Seq[AddressSet]
)(implicit p: Parameters)
extends AXI4SlaveModule(address, executable = false, _extra = new KeyboardIO)
{
......
......@@ -5,22 +5,24 @@ import chisel3._
import chisel3.util._
import freechips.rocketchip.diplomacy.{AddressSet, LazyModule, LazyModuleImp, RegionType}
import xiangshan.HasXSParameter
import utils.{MaskExpand}
class RAMHelper(memByte: BigInt) extends BlackBox with HasXSParameter {
val io = IO(new Bundle {
val clk = Input(Clock())
val rIdx = Input(UInt(DataBits.W))
val clk = Input(Clock())
val en = Input(Bool())
val rIdx = Input(UInt(DataBits.W))
val rdata = Output(UInt(DataBits.W))
val wIdx = Input(UInt(DataBits.W))
val wIdx = Input(UInt(DataBits.W))
val wdata = Input(UInt(DataBits.W))
val wmask = Input(UInt(DataBits.W))
val wen = Input(Bool())
val wen = Input(Bool())
})
}
class AXI4RAM
(
address: AddressSet,
address: Seq[AddressSet],
memByte: Long,
useBlackBox: Boolean = false,
executable: Boolean = true,
......@@ -32,27 +34,35 @@ class AXI4RAM
override lazy val module = new AXI4SlaveModuleImp(this){
val split = beatBytes / 8
val bankByte = memByte / split
val offsetBits = log2Up(memByte)
val offsetMask = (1 << offsetBits) - 1
require(address.length >= 1)
val baseAddress = address(0).base
def index(addr: UInt) = ((addr & offsetMask.U) >> log2Ceil(beatBytes)).asUInt()
def index(addr: UInt) = ((addr - baseAddress.U)(offsetBits - 1, 0) >> log2Ceil(beatBytes)).asUInt()
def inRange(idx: UInt) = idx < (memByte / 8).U
def inRange(idx: UInt) = idx < (memByte / beatBytes).U
val wIdx = index(waddr) + writeBeatCnt
val rIdx = index(raddr) + readBeatCnt
val wen = in.w.fire() && inRange(wIdx)
require(beatBytes >= 8)
val rdata = if (useBlackBox) {
val mem = Module(new RAMHelper(memByte))
mem.io.clk := clock
mem.io.rIdx := rIdx
mem.io.wIdx := wIdx
mem.io.wdata := in.w.bits.data
mem.io.wmask := fullMask
mem.io.wen := wen
mem.io.rdata
val mems = (0 until split).map {_ => Module(new RAMHelper(bankByte))}
mems.zipWithIndex map { case (mem, i) =>
mem.io.clk := clock
mem.io.en := !reset.asBool() && ((state === s_rdata) || (state === s_wdata))
mem.io.rIdx := (rIdx << log2Up(split)) + i.U
mem.io.wIdx := (wIdx << log2Up(split)) + i.U
mem.io.wdata := in.w.bits.data((i + 1) * 64 - 1, i * 64)
mem.io.wmask := MaskExpand(in.w.bits.strb((i + 1) * 8 - 1, i * 8))
mem.io.wen := wen
}
val rdata = mems.map {mem => mem.io.rdata}
Cat(rdata.reverse)
} else {
val mem = Mem(memByte / beatBytes, Vec(beatBytes, UInt(8.W)))
......
......@@ -10,7 +10,7 @@ import xiangshan.HasXSLog
abstract class AXI4SlaveModule[T <: Data]
(
address: AddressSet,
address: Seq[AddressSet],
executable: Boolean = true,
beatBytes: Int = 8,
burstLen: Int = 1,
......@@ -19,7 +19,7 @@ abstract class AXI4SlaveModule[T <: Data]
val node = AXI4SlaveNode(Seq(AXI4SlavePortParameters(
Seq(AXI4SlaveParameters(
Seq(address),
address,
regionType = RegionType.UNCACHED,
executable = executable,
supportsWrite = TransferSizes(1, beatBytes * burstLen),
......@@ -41,6 +41,9 @@ class AXI4SlaveModuleImp[T<:Data](outer: AXI4SlaveModule[T])
})
val (in, edge) = outer.node.in.head
// do not let MMIO AXI signals optimized out
chisel3.dontTouch(in)
// val timer = GTimer()
when(in.ar.fire()){
......@@ -72,9 +75,9 @@ class AXI4SlaveModuleImp[T<:Data](outer: AXI4SlaveModule[T])
assert(in.ar.bits.burst === AXI4Parameters.BURST_INCR, "only support busrt ince!")
}
private val s_idle :: s_rdata :: s_wdata :: s_wresp :: Nil = Enum(4)
val s_idle :: s_rdata :: s_wdata :: s_wresp :: Nil = Enum(4)
private val state = RegInit(s_idle)
val state = RegInit(s_idle)
switch(state){
is(s_idle){
......@@ -150,7 +153,7 @@ class AXI4SlaveModuleImp[T<:Data](outer: AXI4SlaveModule[T])
(c.value, in.w.bits.last)
}
in.aw.ready := state === s_idle
in.aw.ready := state === s_idle && !in.ar.valid
in.w.ready := state === s_wdata
in.b.bits.resp := AXI4Parameters.RESP_OKAY
......
package device
import chisel3._
import chisel3.util.experimental.BoringUtils
import chipsalliance.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy.AddressSet
import utils._
......@@ -13,7 +12,7 @@ class TimerIO extends Bundle {
class AXI4Timer
(
sim: Boolean = false,
address: AddressSet
address: Seq[AddressSet]
)(implicit p: Parameters)
extends AXI4SlaveModule(address, executable = false, _extra = new TimerIO)
{
......@@ -31,12 +30,6 @@ class AXI4Timer
val tick = (nextCnt === freq)
when (tick) { mtime := mtime + inc }
if (sim) {
val isWFI = WireInit(false.B)
BoringUtils.addSink(isWFI, "isWFI")
when (isWFI) { mtime := mtime + 100000.U }
}
val mapping = Map(
RegMap(0x4000, mtimecmp),
RegMap(0x8000, freq),
......
......@@ -4,7 +4,6 @@ import chisel3._
import chisel3.util._
import bus.axi4._
import chipsalliance.rocketchip.config.Parameters
import chisel3.util.experimental.BoringUtils
import freechips.rocketchip.diplomacy.AddressSet
import utils._
......@@ -21,7 +20,7 @@ class UARTIO extends Bundle {
class AXI4UART
(
address: AddressSet
address: Seq[AddressSet]
)(implicit p: Parameters)
extends AXI4SlaveModule(address, executable = false, _extra = new UARTIO)
{
......
......@@ -54,7 +54,7 @@ class VGACtrlBundle extends Bundle {
class VGACtrl
(
address: AddressSet
address: Seq[AddressSet]
)(implicit p: Parameters)
extends AXI4SlaveModule(address, _extra = new VGACtrlBundle, executable = false) with HasVGAParameter {
override lazy val module = new AXI4SlaveModuleImp[VGACtrlBundle](this) {
......@@ -106,8 +106,8 @@ class FBHelper extends BlackBox with HasBlackBoxInline {
class AXI4VGA
(
sim: Boolean = false,
fbAddress: AddressSet,
ctrlAddress: AddressSet
fbAddress: Seq[AddressSet],
ctrlAddress: Seq[AddressSet]
)(implicit p: Parameters)
extends LazyModule with HasVGAParameter {
......
......@@ -4,7 +4,6 @@ import chisel3._
import chisel3.util._
import freechips.rocketchip.tilelink._
import chipsalliance.rocketchip.config._
import chisel3.util.experimental.BoringUtils
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper.RegField
import utils.{HasTLDump, XSDebug}
......@@ -35,12 +34,6 @@ class TLTimer(address: Seq[AddressSet], sim: Boolean)(implicit p: Parameters) ex
val tick = (nextCnt === freq)
when (tick) { mtime := mtime + inc }
if (sim) {
val isWFI = WireInit(false.B)
ExcitingUtils.addSink(isWFI, "isWFI")
when (isWFI) { mtime := mtime + 100000.U }
}
node.regmap( mapping =
0x0000 -> RegField.bytes(msip),
0x4000 -> RegField.bytes(mtimecmp),
......
import chisel3._
import chisel3.util._
package object fpu {
object FPUOpType {
def funcWidth = 6
def FpuOp(fu: String, op: String): UInt = ("b" + fu + op).U(funcWidth.W)
// FMA
def fadd:UInt = FpuOp("000", "000")
def fsub:UInt = FpuOp("000", "001")
def fmadd:UInt = FpuOp("000", "100")
def fmsub:UInt = FpuOp("000", "101")
def fnmsub:UInt = FpuOp("000", "110")
def fnmadd:UInt = FpuOp("000", "111")
def fmul:UInt = FpuOp("000", "010")
// FCMP
def fmin:UInt = FpuOp("001", "000")
def fmax:UInt = FpuOp("001", "001")
def fle:UInt = FpuOp("001", "010")
def flt:UInt = FpuOp("001", "011")
def feq:UInt = FpuOp("001", "100")
// FMV
def fmv_f2i:UInt= FpuOp("010", "000")
def fmv_i2f:UInt= FpuOp("010", "001")
def fclass:UInt = FpuOp("010", "010")
def fsgnj:UInt = FpuOp("010", "110")
def fsgnjn:UInt = FpuOp("010", "101")
def fsgnjx:UInt = FpuOp("010", "100")
// FloatToInt
def f2w:UInt = FpuOp("011", "000")
def f2wu:UInt = FpuOp("011", "001")
def f2l:UInt = FpuOp("011", "010")
def f2lu:UInt = FpuOp("011", "011")
// IntToFloat
def w2f:UInt = FpuOp("100", "000")
def wu2f:UInt = FpuOp("100", "001")
def l2f:UInt = FpuOp("100", "010")
def lu2f:UInt = FpuOp("100", "011")
// FloatToFloat
def s2d:UInt = FpuOp("101", "000")
def d2s:UInt = FpuOp("110", "000")
// Div/Sqrt
def fdiv:UInt = FpuOp("111", "000")
def fsqrt:UInt = FpuOp("111", "001")
}
object FPUIOFunc {
def in_raw = 0.U(1.W)
def in_unbox = 1.U(1.W)
def out_raw = 0.U(2.W)
def out_box = 1.U(2.W)
def out_sext = 2.U(2.W)
def out_zext = 3.U(2.W)
def apply(inputFunc: UInt, outputFunc:UInt) = Cat(inputFunc, outputFunc)
}
class Fflags extends Bundle {
val invalid = Bool() // 4
val infinite = Bool() // 3
val overflow = Bool() // 2
val underflow = Bool() // 1
val inexact = Bool() // 0
}
object RoudingMode {
val RNE = "b000".U(3.W)
val RTZ = "b001".U(3.W)
val RDN = "b010".U(3.W)
val RUP = "b011".U(3.W)
val RMM = "b100".U(3.W)
}
class FloatPoint(val expWidth: Int, val mantWidth:Int) extends Bundle{
val sign = Bool()
val exp = UInt(expWidth.W)
val mant = UInt(mantWidth.W)
def defaultNaN: UInt = Cat(0.U(1.W), Fill(expWidth+1,1.U(1.W)), Fill(mantWidth-1,0.U(1.W)))
def posInf: UInt = Cat(0.U(1.W), Fill(expWidth, 1.U(1.W)), 0.U(mantWidth.W))
def negInf: UInt = Cat(1.U(1.W), posInf.tail(1))
def maxNorm: UInt = Cat(0.U(1.W), Fill(expWidth-1, 1.U(1.W)), 0.U(1.W), Fill(mantWidth, 1.U(1.W)))
def expBias: UInt = Fill(expWidth-1, 1.U(1.W))
def expBiasInt: Int = (1 << (expWidth-1)) - 1
def mantExt: UInt = Cat(exp=/=0.U, mant)
def apply(x: UInt): FloatPoint = x.asTypeOf(new FloatPoint(expWidth, mantWidth))
}
object Float32 extends FloatPoint(8, 23)
object Float64 extends FloatPoint(11, 52)
def expOverflow(sexp: SInt, expWidth: Int): Bool = sexp >= Cat(0.U(1.W), Fill(expWidth, 1.U(1.W))).asSInt()
def expOverflow(uexp: UInt, expWidth: Int): Bool = expOverflow(Cat(0.U(1.W), uexp).asSInt(), expWidth)
def boxF32ToF64(x: UInt): UInt = Cat(Fill(32, 1.U(1.W)), x(31, 0))
def unboxF64ToF32(x: UInt): UInt = Mux(x(63, 32)===Fill(32, 1.U(1.W)), x(31, 0), Float32.defaultNaN)
def extF32ToF64(x: UInt): UInt = {
val f32 = Float32(x)
Cat(
f32.sign,
Mux(f32.exp === 0.U,
0.U(Float64.expWidth.W),
Mux((~f32.exp).asUInt() === 0.U,
Cat("b111".U(3.W), f32.exp),
Cat("b0111".U(4.W) + f32.exp.head(1), f32.exp.tail(1))
)
),
Cat(f32.mant, 0.U((Float64.mantWidth - Float32.mantWidth).W))
)
}
}
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import utils._
class TableAddr(val idxBits: Int) extends NOOPBundle {
def tagBits = VAddrBits - 2 - idxBits
//val res = UInt((AddrBits - VAddrBits).W)
val tag = UInt(tagBits.W)
val idx = UInt(idxBits.W)
val pad = UInt(2.W)//TODO
def fromUInt(x: UInt) = x.asTypeOf(UInt(VAddrBits.W)).asTypeOf(this)
def getTag(x: UInt) = fromUInt(x).tag
def getIdx(x: UInt) = fromUInt(x).idx
}
object BTBtype {
def B = "b00".U // branch
def J = "b01".U // jump
def I = "b10".U // indirect
def R = "b11".U // return
def apply() = UInt(2.W)
}
class BPUUpdateReq extends NOOPBundle {
val valid = Output(Bool())
val pc = Output(UInt(VAddrBits.W))
val isMissPredict = Output(Bool())
val actualTarget = Output(UInt(VAddrBits.W))
val actualTaken = Output(Bool()) // for branch
val fuOpType = Output(FuOpType())
val btbType = Output(BTBtype())
val isRVC = Output(Bool()) // for ras, save PC+2 to stack if is RVC
}
class BPU1 extends NOOPModule {
val io = IO(new Bundle {
val in = new Bundle { val pc = Flipped(Valid((UInt(VAddrBits.W)))) }
val out = new RedirectIO
val flush = Input(Bool())
val brIdx = Output(UInt(3.W))
val lateJump = Output(Bool())
})
val flush = BoolStopWatch(io.flush, io.in.pc.valid, startHighPriority = true)
// BTB
val NRbtb = 512
val btbAddr = new TableAddr(log2Up(NRbtb))
def btbEntry() = new Bundle {
val tag = UInt(btbAddr.tagBits.W)
val _type = UInt(2.W)
val target = UInt(VAddrBits.W)
val brIdx = UInt(3.W)
val valid = Bool()
}
val btb = Module(new SRAMTemplate(btbEntry(), set = NRbtb, shouldReset = true, holdRead = true, singlePort = true))
// flush BTB when executing fence.i
val flushBTB = WireInit(false.B)
val flushTLB = WireInit(false.B)
BoringUtils.addSink(flushBTB, "MOUFlushICache")
BoringUtils.addSink(flushTLB, "MOUFlushTLB")
btb.reset := reset.asBool || (flushBTB || flushTLB)
Debug(false) {
when (reset.asBool || (flushBTB || flushTLB)) {
printf("[BPU-RESET] %d bpu-reset flushBTB:%d flushTLB:%d\n", GTimer(), flushBTB, flushTLB)
}
}
btb.io.r.req.valid := io.in.pc.valid
btb.io.r.req.bits.setIdx := btbAddr.getIdx(io.in.pc.bits)
val btbRead = Wire(btbEntry())
btbRead := btb.io.r.resp.data(0)
// since there is one cycle latency to read SyncReadMem,
// we should latch the input pc for one cycle
val pcLatch = RegEnable(io.in.pc.bits, io.in.pc.valid)
val btbHit = btbRead.tag === btbAddr.getTag(pcLatch) && !flush && RegNext(btb.io.r.req.fire(), init = false.B) && !(pcLatch(1) && btbRead.brIdx(0)) && btbRead.valid
// btbHit will ignore pc(1,0). pc(1,0) is used to build brIdx
// !(pcLatch(1) && btbRead.brIdx(0)) is used to deal with the following case:
// -------------------------------------------------
// 0 jump rvc // marked as "take branch" in BTB
// 2 xxx rvc <-- jump to here
// -------------------------------------------------
val lateJump = btbRead.brIdx(2) && btbHit
io.lateJump := lateJump
// val lateJumpLatch = RegNext(lateJump)
// val lateJumpTarget = RegEnable(btbRead.target, lateJump)
Debug(false){
//printf("[BTBHT] lateJump %x lateJumpLatch %x lateJumpTarget %x\n", lateJump, lateJumpLatch, lateJumpTarget)
when(btbHit){
printf("[BTBHT1] %d pc=%x tag=%x,%x index=%x bridx=%x tgt=%x,%x flush %x type:%x\n", GTimer(), pcLatch, btbRead.tag, btbAddr.getTag(pcLatch), btbAddr.getIdx(pcLatch), btbRead.brIdx, btbRead.target, io.out.target, flush,btbRead._type)
printf("[BTBHT2] btbRead.brIdx %x mask %x\n", btbRead.brIdx, Cat(lateJump, Fill(2, io.out.valid)))
printf("[BTBHT5] btbReqValid:%d btbReqSetIdx:%x\n",btb.io.r.req.valid, btb.io.r.req.bits.setIdx)
}
}
// PHT
val pht = Mem(NRbtb, UInt(2.W))
val phtTaken = RegEnable(pht.read(btbAddr.getIdx(io.in.pc.bits))(1), io.in.pc.valid)
// RAS
val NRras = 16
val ras = Mem(NRras, UInt(VAddrBits.W))
// val raBrIdxs = Mem(NRras, UInt(2.W))
val sp = Counter(NRras)
val rasTarget = RegEnable(ras.read(sp.value), io.in.pc.valid)
// val rasBrIdx = RegEnable(raBrIdxs.read(sp.value), io.in.pc.valid)
// update
val req = WireInit(0.U.asTypeOf(new BPUUpdateReq))
val btbWrite = WireInit(0.U.asTypeOf(btbEntry()))
BoringUtils.addSink(req, "bpuUpdateReq")
Debug(false){
when(req.valid){
printf("[BTBUP] pc=%x tag=%x index=%x bridx=%x tgt=%x type=%x\n", req.pc, btbAddr.getTag(req.pc), btbAddr.getIdx(req.pc), Cat(req.pc(1), ~req.pc(1)), req.actualTarget, req.btbType)
}
}
//val fflag = req.btbType===3.U && btb.io.w.req.valid && btb.io.w.req.bits.setIdx==="hc9".U
//when(fflag && GTimer()>2888000.U) {
// printf("%d\n", GTimer())
// printf("[BTBHT6] btbWrite.type is BTBtype.R/RET!!! Inpc:%x btbWrite.brIdx:%x setIdx:%x\n", io.in.pc.bits, btbWrite.brIdx, btb.io.w.req.bits.setIdx)
// printf("[BTBHT6] tag:%x target:%x _type:%x bridx:%x\n", btbWrite.tag,btbWrite.target,btbWrite._type,btbWrite.brIdx)
// printf(p"[BTBHT6] req:${req} \n")
//}
//printf("[BTBHT5] tag: target:%x type:%d brIdx:%d\n", req.actualTarget, req.btbType, Cat(req.pc(2,0)==="h6".U && !req.isRVC, req.pc(1), ~req.pc(1)))
btbWrite.tag := btbAddr.getTag(req.pc)
btbWrite.target := req.actualTarget
btbWrite._type := req.btbType
btbWrite.brIdx := Cat(req.pc(2,0)==="h6".U && !req.isRVC, req.pc(1), ~req.pc(1))
btbWrite.valid := true.B
// NOTE: We only update BTB at a miss prediction.
// If a miss prediction is found, the pipeline will be flushed
// in the next cycle. Therefore it is safe to use single-port
// SRAM to implement BTB, since write requests have higher priority
// than read request. Again, since the pipeline will be flushed
// in the next cycle, the read request will be useless.
btb.io.w.req.valid := req.isMissPredict && req.valid
btb.io.w.req.bits.setIdx := btbAddr.getIdx(req.pc)
btb.io.w.req.bits.data := btbWrite
//Debug(true) {
//when (btb.io.w.req.valid && btbWrite.tag === btbAddr.getTag("hffffffff803541a4".U)) {
// printf("[BTBWrite] %d setIdx:%x req.valid:%d pc:%x target:%x bridx:%x\n", GTimer(), btbAddr.getIdx(req.pc), req.valid, req.pc, req.actualTarget, btbWrite.brIdx)
//}
//}
//when (GTimer() > 77437484.U && btb.io.w.req.valid) {
// printf("[BTBWrite-ALL] %d setIdx:%x req.valid:%d pc:%x target:%x bridx:%x\n", GTimer(), btbAddr.getIdx(req.pc), req.valid, req.pc, req.actualTarget, btbWrite.brIdx)
//}
val cnt = RegNext(pht.read(btbAddr.getIdx(req.pc)))
val reqLatch = RegNext(req)
when (reqLatch.valid && ALUOpType.isBranch(reqLatch.fuOpType)) {
val taken = reqLatch.actualTaken
val newCnt = Mux(taken, cnt + 1.U, cnt - 1.U)
val wen = (taken && (cnt =/= "b11".U)) || (!taken && (cnt =/= "b00".U))
when (wen) {
pht.write(btbAddr.getIdx(reqLatch.pc), newCnt)
//Debug(){
//printf("BPUPDATE: pc %x cnt %x\n", reqLatch.pc, newCnt)
//}
}
}
when (req.valid) {
when (req.fuOpType === ALUOpType.call) {
ras.write(sp.value + 1.U, Mux(req.isRVC, req.pc + 2.U, req.pc + 4.U))
// raBrIdxs.write(sp.value + 1.U, Mux(req.pc(1), 2.U, 1.U))
sp.value := sp.value + 1.U
}
.elsewhen (req.fuOpType === ALUOpType.ret) {
when(sp.value === 0.U) {
//printf("ATTTTT: sp.value is 0.U\n") //TODO: sp.value may equal to 0.U
}
sp.value := Mux(sp.value===0.U, 0.U, sp.value - 1.U) //TODO: sp.value may less than 0.U
}
}
io.out.target := Mux(btbRead._type === BTBtype.R, rasTarget, btbRead.target)
// io.out.target := Mux(lateJumpLatch && !flush, lateJumpTarget, Mux(btbRead._type === BTBtype.R, rasTarget, btbRead.target))
// io.out.brIdx := btbRead.brIdx & Fill(3, io.out.valid)
io.brIdx := btbRead.brIdx & Cat(true.B, lateJump, Fill(2, io.out.valid))
io.out.valid := btbHit && Mux(btbRead._type === BTBtype.B, phtTaken, true.B && rasTarget=/=0.U) //TODO: add rasTarget=/=0.U, need fix
// io.out.valid := btbHit && Mux(btbRead._type === BTBtype.B, phtTaken, true.B) && !lateJump || lateJumpLatch && !flush && !lateJump
// Note:
// btbHit && Mux(btbRead._type === BTBtype.B, phtTaken, true.B) && !lateJump : normal branch predict
// lateJumpLatch && !flush && !lateJump : cross line branch predict, bpu will require imem to fetch the next 16bit of current inst in next instline
// `&& !lateJump` is used to make sure this logic will run correctly when imem stalls (pcUpdate === false)
// by using `instline`, we mean a 64 bit instfetch result from imem
// ROCKET uses a 32 bit instline, and its IDU logic is more simple than this implentation.
}
class BPU2 extends NOOPModule {
val io = IO(new Bundle {
val in = Flipped(Valid(new CtrlFlowIO))
val out = new RedirectIO
})
val instr = io.in.bits.instr
val immJ = SignExt(Cat(instr(31), instr(19, 12), instr(20), instr(30, 21), 0.U(1.W)), XLEN)
val immB = SignExt(Cat(instr(31), instr(7), instr(30, 25), instr(11, 8), 0.U(1.W)), XLEN)
val table = Array(
RV32I_BRUInstr.JAL -> List(immJ, true.B),
RV32I_BRUInstr.BNE -> List(immB, instr(31)),
RV32I_BRUInstr.BEQ -> List(immB, instr(31)),
RV32I_BRUInstr.BLT -> List(immB, instr(31)),
RV32I_BRUInstr.BGE -> List(immB, instr(31)),
RV32I_BRUInstr.BLTU -> List(immB, instr(31)),
RV32I_BRUInstr.BGEU -> List(immB, instr(31))
)
val default = List(immB, false.B)
val offset :: predict :: Nil = ListLookup(instr, default, table)
io.out.target := io.in.bits.pc + offset
io.out.valid := io.in.valid && predict(0)
}
package noop
import chisel3._
import chisel3.util._
class CtrlSignalIO extends NOOPBundle {
val src1Type = Output(SrcType())
val src2Type = Output(SrcType())
val src3Type = Output(SrcType())
val fuType = Output(FuType())
val fuOpType = Output(FuOpType())
val rfSrc1 = Output(UInt(5.W))
val rfSrc2 = Output(UInt(5.W))
val rfWen = Output(Bool())
val fpWen = Output(Bool())
val fpInputFunc = Output(UInt(1.W))
val fpOutputFunc = Output(UInt(2.W))
val rfDest = Output(UInt(5.W))
val isNoopTrap = Output(Bool())
val isSrc1Forward = Output(Bool())
val isSrc2Forward = Output(Bool())
}
class DataSrcIO extends NOOPBundle {
val src1 = Output(UInt(XLEN.W))
val src2 = Output(UInt(XLEN.W))
val imm = Output(UInt(XLEN.W))
}
class RedirectIO extends NOOPBundle {
val target = Output(UInt(VAddrBits.W))
// val brIdx = Output(UInt(3.W)) // for RVC
val valid = Output(Bool())
}
// class IRIDCtrlFlowIO extends NOOPBundle {
// val instr = Output(UInt(64.W))
// val pc = Output(UInt(VAddrBits.W))
// val pnpc = Output(UInt(VAddrBits.W))
// val brIdx = Output(UInt(3.W))
// val redirect = new RedirectIO
// }
class CtrlFlowIO extends NOOPBundle {
val instr = Output(UInt(64.W))
val pc = Output(UInt(VAddrBits.W))
val pnpc = Output(UInt(VAddrBits.W))
val redirect = new RedirectIO
val exceptionVec = Output(Vec(16, Bool()))
val intrVec = Output(Vec(12, Bool()))
val brIdx = Output(UInt(4.W))
val crossPageIPFFix = Output(Bool())
}
class DecodeIO extends NOOPBundle {
val cf = new CtrlFlowIO
val ctrl = new CtrlSignalIO
val data = new DataSrcIO
}
class WriteBackIO extends NOOPBundle {
val rfWen = Output(Bool())
val fpWen = Output(Bool())
val rfDest = Output(UInt(5.W))
val rfData = Output(UInt(XLEN.W))
}
class CommitIO extends NOOPBundle {
val decode = new DecodeIO
val isMMIO = Output(Bool())
val intrNO = Output(UInt(XLEN.W))
val commits = Output(Vec(FuType.num, UInt(XLEN.W)))
}
class FunctionUnitIO extends NOOPBundle {
val in = Flipped(Decoupled(new Bundle {
val src1 = Output(UInt(XLEN.W))
val src2 = Output(UInt(XLEN.W))
val func = Output(FuOpType())
}))
val out = Decoupled(Output(UInt(XLEN.W)))
}
class ForwardIO extends NOOPBundle {
val valid = Output(Bool())
val wb = new WriteBackIO
val fuType = Output(FuType())
}
class MMUIO extends NOOPBundle {
// val ptev = Output(Bool())
// val pteu = Output(Bool())
// val ptex = Output(Bool())
// val valid = Output(Bool())
// val isStore = Output(Bool())
val priviledgeMode = Input(UInt(2.W))
val status_sum = Input(Bool())
val status_mxr = Input(Bool())
val loadPF = Output(Bool())
val storePF = Output(Bool())
val addr = Output(UInt(VAddrBits.W))
def isPF() = loadPF || storePF
}
class MemMMUIO extends NOOPBundle {
val imem = new MMUIO
val dmem = new MMUIO
}
class TLBExuIO extends NOOPBundle {
val satp = Output(UInt(XLEN.W))
val sfence = new Bundle {
val valid = Output(Bool())
val asid = Output(UInt(9.W))
val vaddr = Output(UInt(XLEN.W))
}
def access(valid: Bool, src1: UInt, src2: UInt, func: UInt, satp: UInt) = {//func no use here for just sfence.vma only
this.sfence.valid := valid
this.sfence.vaddr := src1
this.sfence.asid := src2(8,0)
this.satp := satp
}
}
\ No newline at end of file
此差异已折叠。
package noop
import chisel3._
import chisel3.util._
import noop.isa.{RVDInstr, RVFInstr}
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)
}
// trait CompInstConst {
// val RVCRegNumTable = Array(
// BitPat("b000") -> 8.U,
// BitPat("b001") -> 9.U,
// BitPat("b010") -> 10.U,
// BitPat("b011") -> 11.U,
// BitPat("b100") -> 12.U,
// BitPat("b101") -> 13.U,
// BitPat("b110") -> 14.U,
// BitPat("b111") -> 15.U
// )
// }
object SrcType {
def reg = "b00".U
def pc = "b01".U
def imm = "b01".U
def fp = "b10".U
def apply() = UInt(2.W)
}
object FuType {
def num = 6
def alu = "b000".U
def lsu = "b001".U
def mdu = "b010".U
def csr = "b011".U
def mou = "b100".U
def fpu = "b101".U
def apply() = UInt(log2Up(num).W)
}
object FuOpType {
def apply() = UInt(6.W)
}
object Instructions extends HasInstrType with HasNOOPParameter {
def NOP = 0x00000013.U
val DecodeDefault = List(InstrN, FuType.csr, CSROpType.jmp)
def DecodeTable = RVIInstr.table ++ NOOPTrap.table ++
(if (HasMExtension) RVMInstr.table else Nil) ++
(if (HasCExtension) RVCInstr.table else Nil) ++
(if (HasFPU) RVFInstr.table ++ RVDInstr.table else Nil) ++
Priviledged.table ++
RVAInstr.table ++
RVZicsrInstr.table ++ RVZifenceiInstr.table
}
object CInstructions extends HasInstrType with HasNOOPParameter{
def NOP = 0x00000013.U
val DecodeDefault = List(RVCInstr.ImmNone, RVCInstr.DtCare, RVCInstr.DtCare, RVCInstr.DtCare)
// val DecodeDefault = List(InstrN, FuType.csr, CSROpType.jmp)
def CExtraDecodeTable = RVCInstr.cExtraTable
}
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import utils._
import bus.simplebus._
import noop.fu.FPU
class EXU(implicit val p: NOOPConfig) extends NOOPModule {
val io = IO(new Bundle {
val in = Flipped(Decoupled(new DecodeIO))
val out = Decoupled(new CommitIO)
val flush = Input(Bool())
val dmem = new SimpleBusUC(addrBits = VAddrBits)
val forward = new ForwardIO
val memMMU = Flipped(new MemMMUIO)
})
val src1 = io.in.bits.data.src1
val src2 = io.in.bits.data.src2
val (fuType, fuOpType) = (io.in.bits.ctrl.fuType, io.in.bits.ctrl.fuOpType)
val fuValids = Wire(Vec(FuType.num, Bool()))
(0 until FuType.num).map (i => fuValids(i) := (fuType === i.U) && io.in.valid && !io.flush)
val alu = Module(new ALU)
val aluOut = alu.access(valid = fuValids(FuType.alu), src1 = src1, src2 = src2, func = fuOpType)
alu.io.cfIn := io.in.bits.cf
alu.io.offset := io.in.bits.data.imm
alu.io.out.ready := true.B
val lsu = Module(new LSU)
val lsuTlbPF = WireInit(false.B)
val lsuOut = lsu.access(valid = fuValids(FuType.lsu), src1 = src1, src2 = io.in.bits.data.imm, func = fuOpType, dtlbPF = lsuTlbPF)
lsu.io.wdata := src2
lsu.io.instr := io.in.bits.cf.instr
io.out.bits.isMMIO := lsu.io.isMMIO || (AddressSpace.isMMIO(io.in.bits.cf.pc) && io.out.valid)
io.dmem <> lsu.io.dmem
lsu.io.out.ready := true.B
val mdu = Module(new MDU)
val mduOut = mdu.access(valid = fuValids(FuType.mdu), src1 = src1, src2 = src2, func = fuOpType)
mdu.io.out.ready := true.B
val csr = Module(new CSR)
val csrOut = csr.access(valid = fuValids(FuType.csr), src1 = src1, src2 = src2, func = fuOpType)
csr.io.cfIn := io.in.bits.cf
csr.io.cfIn.exceptionVec(loadAddrMisaligned) := lsu.io.loadAddrMisaligned
csr.io.cfIn.exceptionVec(storeAddrMisaligned) := lsu.io.storeAddrMisaligned
csr.io.instrValid := io.in.valid && !io.flush
io.out.bits.intrNO := csr.io.intrNO
csr.io.out.ready := true.B
csr.io.imemMMU <> io.memMMU.imem
csr.io.dmemMMU <> io.memMMU.dmem
val mou = Module(new MOU)
// mou does not write register
mou.access(valid = fuValids(FuType.mou), src1 = src1, src2 = src2, func = fuOpType)
mou.io.cfIn := io.in.bits.cf
mou.io.out.ready := true.B
val (fpuOut,fpuOutValid) = if(HasFPU){
val fpu = Module(new FPU)
Debug(){
when(io.in.valid){
printf(p"[EXU] at pc=${Hexadecimal(io.in.bits.cf.pc)} " +
p"fpu in valid=${fpu.io.in.valid} " +
p"fpu out valid=${fpu.io.out.valid}\n")
}
}
fpu.io.out.ready := true.B
csr.io.fpu_csr <> fpu.io.fpu_csr
fpu.io.fpWen := io.in.bits.ctrl.fpWen
fpu.io.inputFunc := io.in.bits.ctrl.fpInputFunc
fpu.io.outputFunc := io.in.bits.ctrl.fpOutputFunc
fpu.io.instr := io.in.bits.cf.instr
(fpu.access(fuValids(FuType.fpu), src1, src2, io.in.bits.data.imm, io.in.bits.ctrl.fuOpType), fpu.io.out.valid)
} else {
csr.io.fpu_csr <> DontCare
(0.U,false.B)
}
io.out.bits.decode := DontCare
(io.out.bits.decode.ctrl, io.in.bits.ctrl) match { case (o, i) =>
o.rfWen := i.rfWen && (!lsuTlbPF && !lsu.io.loadAddrMisaligned && !lsu.io.storeAddrMisaligned || !fuValids(FuType.lsu)) && !(csr.io.wenFix && fuValids(FuType.csr))
o.rfDest := i.rfDest
o.fuType := i.fuType
o.fpWen := i.fpWen && (!lsuTlbPF && !lsu.io.loadAddrMisaligned && !lsu.io.storeAddrMisaligned || !fuValids(FuType.lsu)) && !(csr.io.wenFix && fuValids(FuType.csr))
}
io.out.bits.decode.cf.pc := io.in.bits.cf.pc
io.out.bits.decode.cf.instr := io.in.bits.cf.instr
io.out.bits.decode.cf.redirect <>
Mux(mou.io.redirect.valid, mou.io.redirect,
Mux(csr.io.redirect.valid, csr.io.redirect, alu.io.redirect))
Debug(){
//when(mou.io.redirect.valid || csr.io.redirect.valid || alu.io.redirect.valid){
printf("[REDIRECT] inValid:%d mou %x csr %x alu %x \n", io.in.valid, mou.io.redirect.valid, csr.io.redirect.valid, alu.io.redirect.valid)
printf("[REDIRECT] flush: %d mou %x csr %x alu %x\n", io.flush, mou.io.redirect.target, csr.io.redirect.target, alu.io.redirect.target)
//}
}
// FIXME: should handle io.out.ready == false
io.out.valid := io.in.valid && MuxLookup(fuType, true.B, List(
FuType.lsu -> lsu.io.out.valid,
FuType.mdu -> mdu.io.out.valid,
FuType.fpu -> fpuOutValid
))
io.out.bits.commits(FuType.alu) := aluOut
io.out.bits.commits(FuType.lsu) := lsuOut
io.out.bits.commits(FuType.csr) := csrOut
io.out.bits.commits(FuType.mdu) := mduOut
io.out.bits.commits(FuType.mou) := 0.U
io.out.bits.commits(FuType.fpu) := fpuOut
io.in.ready := !io.in.valid || io.out.fire()
io.forward.valid := io.in.valid
io.forward.wb.rfWen := io.in.bits.ctrl.rfWen
io.forward.wb.fpWen := io.in.bits.ctrl.fpWen
io.forward.wb.rfDest := io.in.bits.ctrl.rfDest
io.forward.wb.rfData := Mux(alu.io.out.fire(), aluOut, lsuOut)
io.forward.fuType := io.in.bits.ctrl.fuType
val isBru = ALUOpType.isBru(fuOpType)
BoringUtils.addSource(alu.io.out.fire() && !isBru, "perfCntCondMaluInstr")
BoringUtils.addSource(alu.io.out.fire() && isBru, "perfCntCondMbruInstr")
BoringUtils.addSource(lsu.io.out.fire(), "perfCntCondMlsuInstr")
BoringUtils.addSource(mdu.io.out.fire(), "perfCntCondMmduInstr")
BoringUtils.addSource(csr.io.out.fire(), "perfCntCondMcsrInstr")
if (!p.FPGAPlatform) {
val nooptrap = io.in.bits.ctrl.isNoopTrap && io.in.valid
val cycleCnt = WireInit(0.U(XLEN.W))
val instrCnt = WireInit(0.U(XLEN.W))
BoringUtils.addSink(cycleCnt, "simCycleCnt")
BoringUtils.addSink(instrCnt, "simInstrCnt")
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")
}
}
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import utils._
class IDU1 extends NOOPModule with HasInstrType with HasExceptionNO {
val io = IO(new Bundle {
val in = Flipped(Decoupled(new CtrlFlowIO))
val out = Decoupled(new CtrlFlowIO)
val flush = Input(Bool())
val redirect = new RedirectIO
})
val instr = Wire(UInt(32.W))
val isRVC = instr(1,0) =/= "b11".U
//RVC support FSM
//only ensure pnpc given by this FSM is right. May need flush after 6 offset 32 bit inst
val s_idle :: s_extra :: s_waitnext :: s_waitnext_thenj :: Nil = Enum(4)
val state = RegInit(UInt(2.W), s_idle)
val pcOffsetR = RegInit(UInt(3.W), 0.U)
val pcOffset = Mux(state === s_idle, io.in.bits.pc(2,0), pcOffsetR)
val instIn = Cat(0.U(16.W), io.in.bits.instr)
// val nextState = WireInit(0.U(2.W))
val canGo = WireInit(false.B)
val canIn = WireInit(false.B)
val brIdx = io.in.bits.brIdx
// val brIdx = 0.U
val rvcFinish = pcOffset === 0.U && (!isRVC || brIdx(0)) || pcOffset === 4.U && (!isRVC || brIdx(0)) || pcOffset === 2.U && (isRVC || brIdx(1)) || pcOffset === 6.U && isRVC
// if brIdx(0) (branch taken at inst with offest 0), ignore the rest part of this instline
// just get next pc and instline from IFU
val rvcNext = pcOffset === 0.U && (isRVC && !brIdx(0)) || pcOffset === 4.U && (isRVC && !brIdx(0)) || pcOffset === 2.U && !isRVC && !brIdx(1)
val rvcSpecial = pcOffset === 6.U && !isRVC && !brIdx(2)
val rvcSpecialJump = pcOffset === 6.U && !isRVC && brIdx(2)
val pnpcIsSeq = brIdx(3)
// val pnpcIsSeqRight = io.in.bits.pnpc === (Cat(io.in.bits.pc(VAddrBits-1,2), 0.U(2.W)) + 4.U) // TODO: add a new user bit bpRight to do this
// assert(pnpcIsSeq === pnpcIsSeqRight)
val flushIFU = (state === s_idle || state === s_extra) && rvcSpecial && io.in.valid && !pnpcIsSeq
when(flushIFU){printf("flushIFU at pc %x offset %x timer:%d\n", io.in.bits.pc, pcOffset, GTimer())}
assert(!flushIFU)
val loadNextInstline = (state === s_idle || state === s_extra) && (rvcSpecial || rvcSpecialJump) && io.in.valid && pnpcIsSeq
// val loadNextInstline =false.B
val pcOut = WireInit(0.U(VAddrBits.W))
val pnpcOut = WireInit(0.U(VAddrBits.W))
val specialPCR = Reg(UInt(VAddrBits.W)) // reg for full inst that cross 2 inst line
val specialNPCR = Reg(UInt(VAddrBits.W)) // reg for pnc for full inst jump that cross 2 inst line
val specialInstR = Reg(UInt(16.W))
val specialIPFR = RegInit(Bool(), false.B)
val redirectPC = Cat(io.in.bits.pc(VAddrBits-1,3), 0.U(3.W))+"b1010".U // IDU can got get full inst from a single inst line
val rvcForceLoadNext = (pcOffset === 2.U && !isRVC && io.in.bits.pnpc(2,0) === 4.U && !brIdx(1))
//------------------------------------------------------
// rvcForceLoadNext is used to deal with:
// case 1:
// 8010004a: 406007b7 lui a5,0x40600
// 8010004e: 470d li a4,3
// 80100050: 00e78623 sb a4,12(a5) # 4060000c <_start-0x3faffff4>
// For icache req inst in seq, if there is no rvcForceLoadNext,
// after 8010004e there will be 8010004c instead of 80100050
//------------------------------------------------------
// case 2:
// 80100046: 406007b7 lui a5,0x40600
// 8010004a: 470d li a4,3
// force load next instline into ID stage, if bp wrong, it will be flushed by flushIFU
//------------------------------------------------------
// if there is a j inst in current inst line, a redirect req will be sent by ALU before invalid inst exception being committed
// when brIdx(1), next instline will just be branch target, eatline is no longer needed
// only for test, add this to pipeline when do real implementation
// val predictBranch = io.in.valid && Mux(io.in.bits.pc(1), io.in.bits.pc + 2.U === io.in.bits.pnpc, io.in.bits.pc + 4.U === io.in.bits.pnpc)
// val flush = rvcSpecial
instr := Mux((state === s_waitnext || state === s_waitnext_thenj), Cat(instIn(15,0), specialInstR), LookupTree(pcOffset, List(
"b000".U -> instIn(31,0),
"b010".U -> instIn(31+16,16),
"b100".U -> instIn(63,32),
"b110".U -> instIn(63+16,32+16)
)))
io.redirect.target := redirectPC
io.redirect.valid := flushIFU
when(!io.flush){
switch(state){
is(s_idle){//decode current pc in pipeline
canGo := rvcFinish || rvcNext
canIn := rvcFinish || rvcForceLoadNext
pcOut := io.in.bits.pc
pnpcOut := Mux(rvcFinish, io.in.bits.pnpc, Mux(isRVC, io.in.bits.pc+2.U, io.in.bits.pc+4.U))
when(io.out.fire() && rvcFinish){state := s_idle}
when(io.out.fire() && rvcNext){
state := s_extra
pcOffsetR := pcOffset + Mux(isRVC, 2.U, 4.U)
}
when(rvcSpecial && io.in.valid){
state := s_waitnext
specialPCR := pcOut
specialInstR := io.in.bits.instr(63,63-16+1)
specialIPFR := io.in.bits.exceptionVec(instrPageFault)
}
when(rvcSpecialJump && io.in.valid){
state := s_waitnext_thenj
specialPCR := pcOut
specialNPCR := io.in.bits.pnpc
specialInstR := io.in.bits.instr(63,63-16+1)
specialIPFR := io.in.bits.exceptionVec(instrPageFault)
}
}
is(s_extra){//get 16 aligned inst, pc controled by this FSM
canGo := rvcFinish || rvcNext
canIn := rvcFinish || rvcForceLoadNext
pcOut := Cat(io.in.bits.pc(VAddrBits-1,3), pcOffsetR(2,0))
pnpcOut := Mux(rvcFinish, io.in.bits.pnpc, Mux(isRVC, pcOut+2.U, pcOut+4.U))
when(io.out.fire() && rvcFinish){state := s_idle}
when(io.out.fire() && rvcNext){
state := s_extra
pcOffsetR := pcOffset + Mux(isRVC, 2.U, 4.U)
}
when(rvcSpecial && io.in.valid){
state := s_waitnext
specialPCR := pcOut
specialInstR := io.in.bits.instr(63,63-16+1)
specialIPFR := io.in.bits.exceptionVec(instrPageFault)
}
when(rvcSpecialJump && io.in.valid){
state := s_waitnext_thenj
specialPCR := pcOut
specialNPCR := io.in.bits.pnpc
specialInstR := io.in.bits.instr(63,63-16+1)
specialIPFR := io.in.bits.exceptionVec(instrPageFault)
}
}
is(s_waitnext){//require next 64bits, for this inst has size 32 and offset 6
//ignore bp result, use pc+4 instead
pcOut := specialPCR
pnpcOut := specialPCR + 4.U
// pnpcOut := Mux(rvcFinish, io.in.bits.pnpc, Mux(isRVC, pcOut+2.U, pcOut+4.U))
canGo := io.in.valid
canIn := false.B
when(io.out.fire()){
state := s_extra
pcOffsetR := "b010".U
}
}
is(s_waitnext_thenj){//require next 64bits, for this inst has size 32 and offset 6
//use bp result
pcOut := specialPCR
pnpcOut := specialNPCR
// pnpcOut := Mux(rvcFinish, io.in.bits.pnpc, Mux(isRVC, pcOut+2.U, pcOut+4.U))
canGo := io.in.valid
canIn := true.B
when(io.out.fire()){
state := s_idle
}
}
// is(s_readnext){//npc right, get next 64 inst bits, flush pipeline is not needed
// //ignore bp result, use pc+4 instead
// pcOut := specialPCR
// pnpcOut := specialPCR + 4.U
// // pnpcOut := Mux(rvcFinish, io.in.bits.pnpc, Mux(isRVC, pcOut+2.U, pcOut+4.U))
// canGo := io.in.valid
// canIn := false.B
// when(io.out.fire()){
// state := s_extra
// pcOffsetR := "b010".U
// }
// }
}
}.otherwise{
state := s_idle
canGo := DontCare
canIn := DontCare
pcOut := DontCare
pnpcOut := DontCare
}
//output signals
io.out.bits := DontCare
io.out.bits.redirect.valid := false.B
io.out.bits.pc := pcOut
io.out.bits.pnpc := pnpcOut
io.out.bits.instr := instr
io.out.bits.brIdx := io.in.bits.brIdx
io.out.valid := io.in.valid && canGo
io.in.ready := (!io.in.valid || (io.out.fire() && canIn) || loadNextInstline)
io.out.bits.exceptionVec := io.in.bits.exceptionVec/*.map(_ := false.B)*/ //Fix by zhangzifei from false.B
io.out.bits.exceptionVec(instrPageFault) := io.in.bits.exceptionVec(instrPageFault) || specialIPFR && (state === s_waitnext_thenj || state === s_waitnext)
io.out.bits.crossPageIPFFix := io.in.bits.exceptionVec(instrPageFault) && (state === s_waitnext_thenj || state === s_waitnext) && !specialIPFR
}
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import noop.isa.{RVDInstr, RVFInstr, RVF_LSUInstr, RVD_LSUInstr}
import utils._
class IDU2(implicit val p: NOOPConfig) extends NOOPModule with HasInstrType {
val io = IO(new Bundle {
val in = Flipped(Decoupled(new CtrlFlowIO))
val out = Decoupled(new DecodeIO)
val flush = Input(Bool())
})
val hasIntr = Wire(Bool())
val hasIntrOrExceptino = hasIntr || io.in.bits.exceptionVec(instrPageFault)
val instr = io.in.bits.instr(31, 0)
val decodeList = ListLookup(instr, Instructions.DecodeDefault, Instructions.DecodeTable)
val commonInstrType :: commonFuType :: commonFuOpType :: Nil = decodeList
val intrInstrType :: intrFuType :: intrFuOpType :: Nil = Instructions.DecodeDefault
//(isFp, src1Type, src2Type, src3Type, rfWen, fpWen, fuOpType, inputFunc, outputFunc)
val fpExtraDecodeTable = RVFInstr.extraTable ++ RVDInstr.extraTable
val isFp :: fpSrc1Type :: fpSrc2Type :: fpSrc3Type :: fpRfWen :: fpWen :: fpFuOpType :: fpInputFunc :: fpOutputFunc :: Nil =
if(HasFPU) ListLookup(instr, RVFInstr.extraTableDefault, fpExtraDecodeTable) else RVFInstr.extraTableDefault
val floatLdStInstrs = List(
RVF_LSUInstr.FLW,
RVF_LSUInstr.FSW,
RVD_LSUInstr.FLD,
RVCInstr.C_FLD,
RVCInstr.C_FLDSP,
RVD_LSUInstr.FSD,
RVCInstr.C_FSD,
RVCInstr.C_FSDSP
)
def treeCmp(key: UInt, cmpList: List[BitPat]): Bool = {
cmpList.size match {
case 1 =>
key === cmpList.head
case n =>
treeCmp(key, cmpList take n/2) || treeCmp(key, cmpList drop n/2)
}
}
val isFloatLdSd = if(HasFPU) treeCmp(instr, floatLdStInstrs) else false.B
val isRVFD = isFp.asBool()
val instrType = Mux(hasIntrOrExceptino,
intrInstrType,
commonInstrType
)
val fuType = Mux(hasIntrOrExceptino,
intrFuType,
Mux(isRVFD && !isFloatLdSd,
FuType.fpu,
commonFuType
)
)
val fuOpType = Mux(hasIntrOrExceptino,
intrFuOpType,
Mux(isRVFD, fpFuOpType, commonFuOpType)
)
val isRVC = instr(1,0) =/= "b11".U
val rvcImmType :: rvcSrc1Type :: rvcSrc2Type :: rvcDestType :: Nil =
ListLookup(instr, CInstructions.DecodeDefault, CInstructions.CExtraDecodeTable)
io.out.bits := DontCare
io.out.bits.ctrl.fuType := fuType
io.out.bits.ctrl.fuOpType := fuOpType
io.out.bits.ctrl.fpInputFunc := fpInputFunc
io.out.bits.ctrl.fpOutputFunc := fpOutputFunc
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)
)
val src1Type = Mux(isRVFD,
fpSrc1Type,
LookupTree(instrType, SrcTypeTable.map(p => (p._1, p._2._1)))
)
val src2Type = Mux(isRVFD,
fpSrc2Type,
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 rfWen = !hasIntrOrExceptino && Mux(isRVFD, fpRfWen.asBool(), isrfWen(instrType))
// TODO: refactor decode logic
// make non-register addressing to zero, since isu.sb.isBusy(0) === false.B
io.out.bits.ctrl.rfSrc1 := Mux(src1Type === SrcType.pc, 0.U, rfSrc1)
io.out.bits.ctrl.rfSrc2 := Mux(src2Type === SrcType.imm, 0.U, rfSrc2)
io.out.bits.ctrl.rfWen := rfWen
io.out.bits.ctrl.fpWen := fpWen.asBool()
io.out.bits.ctrl.rfDest := Mux(fpWen.asBool() || rfWen, rfDest, 0.U)
io.out.bits.data := DontCare
val imm = LookupTree(instrType, List(
InstrI -> SignExt(instr(31, 20), XLEN),
InstrS -> 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.bits.data.imm := Mux(isRVC, immrvc, imm)
when (fuType === FuType.alu) {
def isLink(reg: UInt) = (reg === 1.U || reg === 5.U)
when (isLink(rfDest) && fuOpType === ALUOpType.jal) { io.out.bits.ctrl.fuOpType := ALUOpType.call }
when (fuOpType === ALUOpType.jalr) {
when (isLink(rfSrc1)) { io.out.bits.ctrl.fuOpType := ALUOpType.ret }
when (isLink(rfDest)) { io.out.bits.ctrl.fuOpType := ALUOpType.call }
}
}
// fix LUI
io.out.bits.ctrl.src1Type := Mux(instr(6,0) === "b0110111".U, SrcType.reg, src1Type)
io.out.bits.ctrl.src2Type := src2Type
io.out.bits.ctrl.src3Type := fpSrc3Type
// io.out.bits.ctrl.isInvOpcode := (instrType === InstrN) && io.in.valid
io.out.bits.ctrl.isNoopTrap := (instr(31,0) === NOOPTrap.TRAP) && io.in.valid
//output signals
io.out.valid := io.in.valid
io.in.ready := !io.in.valid || io.out.fire() && !hasIntr
io.out.bits.cf <> io.in.bits
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)}
}
val intrVec = WireInit(0.U(12.W))
BoringUtils.addSink(intrVec, "intrVecIDU")
io.out.bits.cf.intrVec.zip(intrVec.asBools).map{ case(x, y) => x := y }
hasIntr := intrVec.orR
io.out.bits.cf.exceptionVec.map(_ := false.B)
io.out.bits.cf.exceptionVec(illegalInstr) := (!isRVFD && instrType === InstrN && !hasIntr) && io.in.valid
io.out.bits.cf.exceptionVec(instrPageFault) := io.in.bits.exceptionVec(instrPageFault)
io.out.bits.ctrl.isNoopTrap := (instr === NOOPTrap.TRAP) && io.in.valid
if (!p.FPGAPlatform) {
val isWFI = (instr === Priviledged.WFI) && io.in.valid
BoringUtils.addSource(isWFI, "isWFI")
}
}
// Note
// C.LWSP is only valid when rd̸=x0; the code points with rd=x0 are reserved
// C.LDSP is only valid when rd̸=x0; the code points with rd=x0 are reserved.
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import utils._
import bus.simplebus._
trait HasResetVector {
val resetVector = 0x40000000L//TODO: set reset vec
}
class IFU extends NOOPModule with HasResetVector {
val io = IO(new Bundle {
val imem = new SimpleBusUC(userBits = VAddrBits*2 + 4, addrBits = VAddrBits)
// val pc = Input(UInt(VAddrBits.W))
val out = Decoupled(new CtrlFlowIO)
val redirect = Flipped(new RedirectIO)
val flushVec = Output(UInt(4.W))
val bpFlush = Output(Bool())
val ipf = Input(Bool())
})
// pc
val pc = RegInit(resetVector.U(VAddrBits.W))
val pcUpdate = io.redirect.valid || io.imem.req.fire()
val snpc = Mux(pc(1), pc + 2.U, pc + 4.U) // sequential next pc
val bp1 = Module(new BPU1)
//
val lateJump = bp1.io.lateJump
val lateJumpLatch = RegInit(false.B)
when(pcUpdate || bp1.io.flush) {
lateJumpLatch := Mux(bp1.io.flush, false.B, lateJump && !lateJumpLatch)
}
val lateJumpTarget = RegEnable(bp1.io.out.target, lateJump)
val lateJumpForceSeq = lateJump && bp1.io.out.valid
val lateJumpForceTgt = lateJumpLatch && !bp1.io.flush
// predicted next pc
val pnpc = Mux(lateJump, snpc, bp1.io.out.target)
val pbrIdx = bp1.io.brIdx
val npc = Mux(io.redirect.valid, io.redirect.target, Mux(lateJumpLatch, lateJumpTarget, Mux(bp1.io.out.valid, pnpc, snpc)))
val npcIsSeq = Mux(io.redirect.valid , false.B, Mux(lateJumpLatch, false.B, Mux(lateJump, true.B, Mux(bp1.io.out.valid, false.B, true.B))))
// Debug(){
// printf("[NPC] %x %x %x %x %x %x\n",lateJumpLatch, lateJumpTarget, lateJump, bp1.io.out.valid, pnpc, snpc)
// }
// val npc = Mux(io.redirect.valid, io.redirect.target, Mux(io.redirectRVC.valid, io.redirectRVC.target, snpc))
val brIdx = Wire(UInt(4.W))
// brIdx(0) -> branch at pc offset 0 (mod 4)
// brIdx(1) -> branch at pc offset 2 (mod 4)
// brIdx(2) -> branch at pc offset 6 (mod 8), and this inst is not rvc inst
brIdx := Cat(npcIsSeq, Mux(io.redirect.valid, 0.U, pbrIdx))
//TODO: BP will be disabled shortly after a redirect request
bp1.io.in.pc.valid := io.imem.req.fire() // only predict when Icache accepts a request
bp1.io.in.pc.bits := npc // predict one cycle early
// bp1.io.flush := io.redirect.valid
bp1.io.flush := io.redirect.valid
//val bp2 = Module(new BPU2)
//bp2.io.in.bits := io.out.bits
//bp2.io.in.valid := io.imem.resp.fire()
when (pcUpdate) {
pc := npc
// printf("[IF1] pc=%x\n", pc)
}
Debug(){
when(pcUpdate) {
printf("[IFUPC] pc:%x pcUpdate:%d npc:%x RedValid:%d RedTarget:%x LJL:%d LJTarget:%x LJ:%d snpc:%x bpValid:%d pnpn:%x \n",pc, pcUpdate, npc, io.redirect.valid,io.redirect.target,lateJumpLatch,lateJumpTarget,lateJump,snpc,bp1.io.out.valid,pnpc)
//printf(p"[IFUIN] redirect: ${io.redirect} \n")
}
}
io.flushVec := Mux(io.redirect.valid, "b1111".U, 0.U)
io.bpFlush := false.B
io.imem.req.bits.apply(addr = Cat(pc(VAddrBits-1,1),0.U(1.W)), //cache will treat it as Cat(pc(63,3),0.U(3.W))
size = "b11".U, cmd = SimpleBusCmd.read, wdata = 0.U, wmask = 0.U, user = Cat(brIdx(3,0), npc(VAddrBits-1, 0), pc(VAddrBits-1, 0)))
io.imem.req.valid := io.out.ready
//TODO: add ctrlFlow.exceptionVec
io.imem.resp.ready := io.out.ready || io.flushVec(0)
io.out.bits := DontCare
//inst path only uses 32bit inst, get the right inst according to pc(2)
Debug(){
when(io.imem.req.fire()){
printf("[IFI] pc=%x user=%x %x %x %x \n", io.imem.req.bits.addr, io.imem.req.bits.user.getOrElse(0.U), io.redirect.valid, pbrIdx, brIdx)
}
when (io.out.fire()) {
printf("[IFO] pc=%x inst=%x\n", io.out.bits.pc, io.out.bits.instr)
}
}
// io.out.bits.instr := (if (XLEN == 64) io.imem.resp.bits.rdata.asTypeOf(Vec(2, UInt(32.W)))(io.out.bits.pc(2))
// else io.imem.resp.bits.rdata)
io.out.bits.instr := io.imem.resp.bits.rdata
io.imem.resp.bits.user.map{ case x =>
io.out.bits.pc := x(VAddrBits-1,0)
io.out.bits.pnpc := x(VAddrBits*2-1,VAddrBits)
io.out.bits.brIdx := x(VAddrBits*2 + 3, VAddrBits*2)
}
io.out.bits.exceptionVec(instrPageFault) := io.ipf
io.out.valid := io.imem.resp.valid && !io.flushVec(0)
BoringUtils.addSource(BoolStopWatch(io.imem.req.valid, io.imem.resp.fire()), "perfCntCondMimemStall")
BoringUtils.addSource(io.flushVec.orR, "perfCntCondMifuFlush")
}
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import utils._
trait HasRegFileParameter {
val NRReg = 32
}
class RegFile(width:Int, hasZero:Boolean = true) extends HasRegFileParameter with HasNOOPParameter {
val rf = Mem(NRReg, UInt(width.W))
def read(addr: UInt) : UInt = if(hasZero) Mux(addr === 0.U, 0.U, rf(addr)) else rf(addr)
def write(addr: UInt, data: UInt) = { rf(addr) := data }
}
class ScoreBoard(hasZero:Boolean = true) extends HasRegFileParameter {
val busy = RegInit(0.U(NRReg.W))
def isBusy(idx: UInt): Bool = busy(idx)
def mask(idx: UInt) = (1.U(NRReg.W) << idx)(NRReg-1, 0)
def update(setMask: UInt, clearMask: UInt) = {
// When clearMask(i) and setMask(i) are both set, setMask(i) wins.
// This can correctly record the busy bit when reg(i) is written
// and issued at the same cycle.
// Note that rf(0) is always free when hasZero==true.
if(hasZero) busy := Cat(((busy & ~clearMask) | setMask)(NRReg-1, 1), 0.U(1.W))
else busy := ((busy & ~clearMask) | setMask)
}
}
class ISU(implicit val p: NOOPConfig) extends NOOPModule with HasRegFileParameter {
val io = IO(new Bundle {
val in = Flipped(Decoupled(new DecodeIO))
val out = Decoupled(new DecodeIO)
val wb = Flipped(new WriteBackIO)
val flush = Input(Bool())
val forward = Flipped(new ForwardIO)
})
io.out.bits := DontCare
val rfSrc1 = io.in.bits.ctrl.rfSrc1
val rfSrc2 = io.in.bits.ctrl.rfSrc2
val rfDest = io.in.bits.ctrl.rfDest
def isDepend(rfSrc: UInt, rfDest: UInt, wen: Bool): Bool = (rfSrc =/= 0.U) && (rfSrc === rfDest) && wen
val forwardRfWen = io.forward.wb.rfWen && io.forward.valid
val dontForward = (io.forward.fuType =/= FuType.alu) && (io.forward.fuType =/= FuType.lsu)
val src1DependEX = isDepend(rfSrc1, io.forward.wb.rfDest, forwardRfWen)
val src2DependEX = isDepend(rfSrc2, io.forward.wb.rfDest, forwardRfWen)
val src1DependWB = isDepend(rfSrc1, io.wb.rfDest, io.wb.rfWen)
val src2DependWB = isDepend(rfSrc2, io.wb.rfDest, io.wb.rfWen)
val src1ForwardNextCycle = src1DependEX && !dontForward
val src2ForwardNextCycle = src2DependEX && !dontForward
val src1Forward = src1DependWB && Mux(dontForward, !src1DependEX, true.B)
val src2Forward = src2DependWB && Mux(dontForward, !src2DependEX, true.B)
val sb = new ScoreBoard
val src1Ready = !sb.isBusy(rfSrc1) || src1ForwardNextCycle || src1Forward
val src2Ready = !sb.isBusy(rfSrc2) || src2ForwardNextCycle || src2Forward
val fpr = new RegFile(width = XLEN, hasZero = false)
val (fprSrcReady,fprSrcData):(Bool,Array[UInt]) = if(HasFPU){
val fsb = new ScoreBoard(hasZero = false)
val forwardFpWen = io.forward.wb.fpWen && io.forward.valid
when (io.wb.fpWen) {
fpr.write(io.wb.rfDest, io.wb.rfData)
}
val fsbClearMask = Mux(io.wb.fpWen && !isDepend(io.wb.rfDest, io.forward.wb.rfDest, forwardFpWen),
fsb.mask(io.wb.rfDest), 0.U(NRReg.W))
val fsbSetMask = Mux(io.out.fire() && io.in.bits.ctrl.fpWen, fsb.mask(rfDest), 0.U)
when (io.flush) { fsb.update(0.U, Fill(NRReg, 1.U(1.W))) }
.otherwise { fsb.update(fsbSetMask, fsbClearMask) }
val instr = io.in.bits.cf.instr
val (fpSrc1,fpSrc2,fpSrc3) = (rfSrc1, rfSrc2, instr(31, 27))
val srcs = Seq(fpSrc1, fpSrc2, fpSrc3).zip(Seq(
io.in.bits.ctrl.src1Type,
io.in.bits.ctrl.src2Type,
io.in.bits.ctrl.src3Type
))
val dataVec = Array.fill(3)(Wire(UInt(XLEN.W)))
// result
(srcs.zipWithIndex.map({
case ((src, t),i) =>
val dependEX = isDepend(src, io.forward.wb.rfDest, forwardFpWen)
val dependWB = isDepend(src, io.wb.rfDest, io.wb.fpWen)
val forwardEX = dependEX && !dontForward
val forwardWB = dependWB && Mux(dontForward, !dependEX, true.B)
dataVec(i) := MuxCase(fpr.read(src), Seq(
forwardEX -> io.forward.wb.rfData,
forwardWB -> io.wb.rfData
))
(!fsb.busy(src) || forwardEX || forwardWB) || (t =/= SrcType.fp)
}).reduceLeft(_ && _), dataVec)
} else (true.B, Array.fill(3)(0.U))
io.out.valid := io.in.valid && src1Ready && src2Ready && fprSrcReady
val rf = new RegFile(XLEN)
// io.out.bits.data.src1 := Mux1H(List(
// (io.in.bits.ctrl.src1Type === SrcType.pc) -> SignExt(io.in.bits.cf.pc, AddrBits),
// src1ForwardNextCycle -> io.forward .wb.rfData,
// (src1Forward && !src1ForwardNextCycle) -> io.wb.rfData,
// ((io.in.bits.ctrl.src1Type =/= SrcType.pc) && !src1ForwardNextCycle && !src1Forward) -> rf.read(rfSrc1)
// ))
// io.out.bits.data.src2 := Mux1H(List(
// (io.in.bits.ctrl.src2Type =/= SrcType.reg) -> io.in.bits.data.imm,
// src2ForwardNextCycle -> io.forward.wb.rfData,
// (src2Forward && !src2ForwardNextCycle) -> io.wb.rfData,
// ((io.in.bits.ctrl.src2Type === SrcType.reg) && !src2ForwardNextCycle && !src2Forward) -> rf.read(rfSrc2)
// ))
io.out.bits.data.src1 := MuxCase(rf.read(rfSrc1), Seq(
(io.in.bits.ctrl.src1Type === SrcType.fp) -> fprSrcData(0),
(io.in.bits.ctrl.src1Type === SrcType.pc) -> SignExt(io.in.bits.cf.pc, AddrBits),
src1ForwardNextCycle -> io.forward.wb.rfData,
src1Forward -> io.wb.rfData
))
io.out.bits.data.src2 := MuxCase(rf.read(rfSrc2), Seq(
(io.in.bits.ctrl.src2Type === SrcType.fp) -> fprSrcData(1),
(io.in.bits.ctrl.src2Type =/= SrcType.reg) -> io.in.bits.data.imm,
src2ForwardNextCycle -> io.forward.wb.rfData,
src2Forward -> io.wb.rfData
))
io.out.bits.data.imm := Mux(io.in.bits.ctrl.src3Type===SrcType.fp, fprSrcData(2), io.in.bits.data.imm)
io.out.bits.cf <> io.in.bits.cf
io.out.bits.ctrl := io.in.bits.ctrl
io.out.bits.ctrl.isSrc1Forward := src1ForwardNextCycle
io.out.bits.ctrl.isSrc2Forward := src2ForwardNextCycle
when (io.wb.rfWen) { rf.write(io.wb.rfDest, io.wb.rfData) }
val wbClearMask = Mux(io.wb.rfWen && !isDepend(io.wb.rfDest, io.forward.wb.rfDest, forwardRfWen), sb.mask(io.wb.rfDest), 0.U(NRReg.W))
val isuFireSetMask = Mux(io.out.fire() && io.in.bits.ctrl.rfWen, sb.mask(rfDest), 0.U)
when (io.flush) { sb.update(0.U, Fill(NRReg, 1.U(1.W))) }
.otherwise { sb.update(isuFireSetMask, wbClearMask) }
io.in.ready := !io.in.valid || io.out.fire()
// read after write
BoringUtils.addSource(io.in.valid && !io.out.valid, "perfCntCondMrawStall")
BoringUtils.addSource(io.out.valid && !io.out.fire(), "perfCntCondMexuBusy")
if (!p.FPGAPlatform) {
val gRegs = (0 until NRReg).map(i => rf.read(i.U))
val fRegs = (0 until NRReg).map(i => if(HasFPU) fpr.read(i.U) else 0.U)
BoringUtils.addSource(VecInit(gRegs ++ fRegs), "difftestRegs")
}
}
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import bus.simplebus._
import bus.axi4._
import utils._
trait HasNOOPParameter {
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 AddrBytes = AddrBits / 8 // unused
val DataBits = XLEN
val DataBytes = DataBits / 8
val HasFPU = true
}
abstract class NOOPModule extends Module with HasNOOPParameter with HasExceptionNO
abstract class NOOPBundle extends Bundle with HasNOOPParameter
case class NOOPConfig (
FPGAPlatform: Boolean = true,
EnableDebug: Boolean = false
)
object AddressSpace {
// (start, size)
def mmio = List((0x0000000040000000L, 0x0000000010000000L))
def dram = (0x0000000080000000L, 0x0000000010000000L)
//def isMMIO(addr: UInt) = mmio.map(range => ((addr & ~((range._2 - 1).U(32.W))) === range._1.U)).reduce(_ || _)
def isMMIO(addr: UInt) = addr(31,28) === "h4".U
}
class NOOP(implicit val p: NOOPConfig) extends NOOPModule {
val io = IO(new Bundle {
val imem = new SimpleBusC
val dmem = new SimpleBusC
val mmio = new SimpleBusUC
val frontend = Flipped(new SimpleBusUC)
})
val ifu = Module(new IFU)
val idu1 = Module(new IDU1)
val idu2 = Module(new IDU2)
val isu = Module(new ISU)
val exu = Module(new EXU)
val wbu = Module(new WBU)
def pipelineConnect2[T <: Data](left: DecoupledIO[T], right: DecoupledIO[T],
isFlush: Bool, entries: Int = 4, pipe: Boolean = false) = {
right <> FlushableQueue(left, isFlush, entries = entries, pipe = pipe)
}
pipelineConnect2(ifu.io.out, idu1.io.in, ifu.io.flushVec(0))
PipelineConnect(idu1.io.out, idu2.io.in, idu2.io.out.fire(), ifu.io.flushVec(1))
PipelineConnect(idu2.io.out, isu.io.in, isu.io.out.fire(), ifu.io.flushVec(1))
PipelineConnect(isu.io.out, exu.io.in, exu.io.out.fire(), ifu.io.flushVec(2))
PipelineConnect(exu.io.out, wbu.io.in, true.B, ifu.io.flushVec(3))
idu1.io.flush := ifu.io.flushVec(1)
idu2.io.flush := ifu.io.flushVec(1)
isu.io.flush := ifu.io.flushVec(2)
exu.io.flush := ifu.io.flushVec(3)
Debug() {
printf("------------------------ TIMER: %d ------------------------\n", GTimer())
printf("flush = %b, ifu:(%d,%d), idu1:(%d,%d), idu2:(%d,%d), isu:(%d,%d), exu:(%d,%d), wbu: (%d,%d)\n",
ifu.io.flushVec.asUInt, ifu.io.out.valid, ifu.io.out.ready,
idu1.io.in.valid, idu1.io.in.ready, idu2.io.in.valid, idu2.io.in.ready, isu.io.in.valid, isu.io.in.ready,
exu.io.in.valid, exu.io.in.ready, wbu.io.in.valid, wbu.io.in.ready)
when (ifu.io.out.valid) { printf("IFU: pc = 0x%x, instr = 0x%x, pnpc = 0x%x\n", ifu.io.out.bits.pc, ifu.io.out.bits.instr, ifu.io.out.bits.pnpc)} ;
when (idu1.io.in.valid) { printf("ID1: pc = 0x%x, instr = 0x%x, pnpc = 0x%x\n", idu1.io.in.bits.pc, idu1.io.in.bits.instr, idu1.io.in.bits.pnpc) }
when (idu2.io.in.valid) { printf("ID2: pc = 0x%x, instr = 0x%x, pnpc = 0x%x\n", idu2.io.in.bits.pc, idu2.io.in.bits.instr, idu2.io.in.bits.pnpc) }
when (isu.io.in.valid) { printf("ISU: pc = 0x%x, pnpc = 0x%x\n", isu.io.in.bits.cf.pc, isu.io.in.bits.cf.pnpc)} ;
when (exu.io.in.valid) { printf("EXU: pc = 0x%x, pnpc = 0x%x\n", exu.io.in.bits.cf.pc, exu.io.in.bits.cf.pnpc)} ;
when (wbu.io.in.valid) { printf("WBU: pc = 0x%x rfWen:%d rfDest:%d rfData:%x Futype:%x\n", wbu.io.in.bits.decode.cf.pc, wbu.io.in.bits.decode.ctrl.rfWen, wbu.io.in.bits.decode.ctrl.rfDest, wbu.io.wb.rfData, wbu.io.in.bits.decode.ctrl.fuType )}
// when (io.in.valid) { printf("TIMER: %d WBU: pc = 0x%x wen %x wdata %x mmio %x intrNO %x\n", GTimer(), io.in.bits.decode.cf.pc, io.wb.rfWen, io.wb.rfData, io.in.bits.isMMIO, io.in.bits.intrNO) }
// printf(p"IFUO: redirectIO:${ifu.io.out.bits.redirect}\n") ; printf("IFUO: exceptionVec: %x\n", ifu.io.out.bits.exceptionVec.asUInt)}
// printf(p"IDUO: redirectIO:${idu.io.out.bits.cf.redirect} redirectIOC:${idu.io.redirect}\n") ; printf("IDUO: exceptionVec:%x\n", idu.io.out.bits.cf.exceptionVec.asUInt)}
// printf(p"ISUO: ${isu.io.out.bits.cf.redirect}\n") ; printf("ISUO: exceptionVec:%x\n", isu.io.out.bits.cf.exceptionVec.asUInt)}
when (exu.io.out.bits.decode.cf.redirect.valid) { printf("EXUO: redirect valid:%d target:%x\n", exu.io.out.bits.decode.cf.redirect.valid, exu.io.out.bits.decode.cf.redirect.target) }
// when (wbu.io.in.valid) { printf("WBU: pc = 0x%x rfWen:%d rfDest:%d rfData:%x Futype:%x commits(0):%x commits(1):%x commits(3):%x\n", wbu.io.in.bits.decode.cf.pc, wbu.io.in.bits.decode.ctrl.rfWen, wbu.io.in.bits.decode.ctrl.rfDest, wbu.io.wb.rfData, wbu.io.in.bits.decode.ctrl.fuType, wbu.io.in.bits.commits(0), wbu.io.in.bits.commits(1), wbu.io.in.bits.commits(3)) }
}
isu.io.wb <> wbu.io.wb
ifu.io.redirect <> wbu.io.redirect
// forward
isu.io.forward <> exu.io.forward
val mmioXbar = Module(new SimpleBusCrossbarNto1(if (HasDcache) 2 else 3))
val dmemXbar = Module(new SimpleBusCrossbarNto1(4))
val itlb = TLB(in = ifu.io.imem, mem = dmemXbar.io.in(1), flush = ifu.io.flushVec(0) | ifu.io.bpFlush, csrMMU = exu.io.memMMU.imem)(TLBConfig(name = "itlb", userBits = VAddrBits*2 + 4, totalEntry = 4))
ifu.io.ipf := itlb.io.ipf
io.imem <> Cache(in = itlb.io.out, mmio = mmioXbar.io.in.take(1), flush = Fill(2, ifu.io.flushVec(0) | ifu.io.bpFlush), empty = itlb.io.cacheEmpty)(
CacheConfig(ro = true, name = "icache", userBits = VAddrBits*2 + 4))
val dtlb = TLB(in = exu.io.dmem, mem = dmemXbar.io.in(2), flush = false.B, csrMMU = exu.io.memMMU.dmem)(TLBConfig(name = "dtlb", totalEntry = 64))
dmemXbar.io.in(0) <> dtlb.io.out
io.dmem <> Cache(in = dmemXbar.io.out, mmio = mmioXbar.io.in.drop(1), flush = "b00".U, empty = dtlb.io.cacheEmpty, enable = HasDcache)(CacheConfig(ro = false, name = "dcache"))
// Make DMA access through L1 DCache to keep coherence
dmemXbar.io.in(3) <> io.frontend
io.mmio <> mmioXbar.io.out
}
package noop
import chisel3._
import chisel3.util._
object NOOPTrap extends HasInstrType {
def StateGoodTrap = 0.U
def StateBadTrap = 1.U
def StateInvOpcode = 2.U
def StateRunning = 3.U
def TRAP = BitPat("b????????????_?????_000_?????_1101011")
val table = Array(TRAP -> List(InstrI, FuType.alu, ALUOpType.add))
}
此差异已折叠。
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import utils._
class WBU(implicit val p: NOOPConfig) extends NOOPModule{
val io = IO(new Bundle {
val in = Flipped(Decoupled(new CommitIO))
val wb = new WriteBackIO
val redirect = new RedirectIO
})
io.wb.rfWen := io.in.bits.decode.ctrl.rfWen && io.in.valid
io.wb.fpWen := io.in.bits.decode.ctrl.fpWen && io.in.valid
io.wb.rfDest := io.in.bits.decode.ctrl.rfDest
io.wb.rfData := io.in.bits.commits(io.in.bits.decode.ctrl.fuType)
io.in.ready := true.B
io.redirect := io.in.bits.decode.cf.redirect
io.redirect.valid := io.in.bits.decode.cf.redirect.valid && io.in.valid
Debug(){
when (io.in.valid) { printf("[COMMIT] TIMER: %d WBU: pc = 0x%x inst %x wen %x wdata %x mmio %x intrNO %x\n", GTimer(), io.in.bits.decode.cf.pc, io.in.bits.decode.cf.instr, io.wb.rfWen, io.wb.rfData, io.in.bits.isMMIO, io.in.bits.intrNO) }
}
BoringUtils.addSource(io.in.valid, "perfCntCondMinstret")
if (!p.FPGAPlatform) {
BoringUtils.addSource(RegNext(io.in.valid), "difftestCommit")
BoringUtils.addSource(RegNext(SignExt(io.in.bits.decode.cf.pc, AddrBits)), "difftestThisPC")
BoringUtils.addSource(RegNext(io.in.bits.decode.cf.instr), "difftestThisINST")
BoringUtils.addSource(RegNext(io.in.bits.isMMIO), "difftestIsMMIO")
BoringUtils.addSource(RegNext(io.in.bits.decode.cf.instr(1,0)=/="b11".U), "difftestIsRVC")
BoringUtils.addSource(RegNext(io.in.bits.intrNO), "difftestIntrNO")
} else {
BoringUtils.addSource(io.in.valid, "ilaWBUvalid")
BoringUtils.addSource(io.in.bits.decode.cf.pc, "ilaWBUpc")
BoringUtils.addSource(io.wb.rfWen, "ilaWBUrfWen")
BoringUtils.addSource(io.wb.rfDest, "ilaWBUrfDest")
BoringUtils.addSource(io.wb.rfData, "ilaWBUrfData")
}
}
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import utils._
object ALUOpType {
def add = "b000000".U
def sll = "b000001".U
def slt = "b000010".U
def sltu = "b000011".U
def xor = "b000100".U
def srl = "b000101".U
def or = "b000110".U
def and = "b000111".U
def sub = "b001000".U
def sra = "b001101".U
def addw = "b100000".U
def subw = "b101000".U
def sllw = "b100001".U
def srlw = "b100101".U
def sraw = "b101101".U
def isWordOp(func: UInt) = func(5)
def jal = "b011000".U
def jalr = "b011010".U
// def cjalr= "b111010".U // pc + 2 instead of 4
def beq = "b010000".U
def bne = "b010001".U
def blt = "b010100".U
def bge = "b010101".U
def bltu = "b010110".U
def bgeu = "b010111".U
// for RAS
def call = "b011100".U
def ret = "b011110".U
def isBru(func: UInt) = func(4)//[important]
def pcPlus2(func: UInt) = func(5)//[important]
def isBranch(func: UInt) = !func(3)
def isJump(func: UInt) = isBru(func) && !isBranch(func)
def getBranchType(func: UInt) = func(2, 1)
def isBranchInvert(func: UInt) = func(0)
}
class ALUIO extends FunctionUnitIO {
val cfIn = Flipped(new CtrlFlowIO)
val redirect = new RedirectIO
val offset = Input(UInt(XLEN.W))
}
class ALU extends NOOPModule {
val io = IO(new ALUIO)
val (valid, src1, src2, func) = (io.in.valid, io.in.bits.src1, io.in.bits.src2, io.in.bits.func)
def access(valid: Bool, src1: UInt, src2: UInt, func: UInt): UInt = {
this.valid := valid
this.src1 := src1
this.src2 := src2
this.func := func
io.out.bits
}
val isAdderSub = (func =/= ALUOpType.add) && (func =/= ALUOpType.addw) && !ALUOpType.isJump(func)
val adderRes = (src1 +& (src2 ^ Fill(XLEN, isAdderSub))) + isAdderSub
val xorRes = src1 ^ src2
val sltu = !adderRes(XLEN)
val slt = xorRes(XLEN-1) ^ sltu
val shsrc1 = LookupTreeDefault(func, src1, List(
ALUOpType.srlw -> ZeroExt(src1(31,0), 64),
ALUOpType.sraw -> SignExt(src1(31,0), 64)
))
val shamt = Mux(ALUOpType.isWordOp(func), src2(4, 0), src2(5, 0))
val res = LookupTreeDefault(func(3, 0), adderRes, List(
ALUOpType.sll -> ((shsrc1 << shamt)(XLEN-1, 0)),
ALUOpType.slt -> ZeroExt(slt, XLEN),
ALUOpType.sltu -> ZeroExt(sltu, XLEN),
ALUOpType.xor -> xorRes,
ALUOpType.srl -> (shsrc1 >> shamt),
ALUOpType.or -> (src1 | src2),
ALUOpType.and -> (src1 & src2),
ALUOpType.sra -> ((shsrc1.asSInt >> shamt).asUInt)
))
val aluRes = Mux(ALUOpType.isWordOp(func), SignExt(res(31,0), 64), res)
val branchOpTable = List(
ALUOpType.getBranchType(ALUOpType.beq) -> !xorRes.orR,
ALUOpType.getBranchType(ALUOpType.blt) -> slt,
ALUOpType.getBranchType(ALUOpType.bltu) -> sltu
)
val isBranch = ALUOpType.isBranch(func)
val isBru = ALUOpType.isBru(func)
// val pcPlus2 = ALUOpType.pcPlus2(func)
val taken = LookupTree(ALUOpType.getBranchType(func), branchOpTable) ^ ALUOpType.isBranchInvert(func)
val target = Mux(isBranch, io.cfIn.pc + io.offset, adderRes)(VAddrBits-1,0)
val predictWrong = (io.redirect.target =/= io.cfIn.pnpc)
val isRVC = (io.cfIn.instr(1,0) =/= "b11".U)
io.redirect.target := Mux(!taken && isBranch, Mux(isRVC, io.cfIn.pc + 2.U, io.cfIn.pc + 4.U), target)
// with branch predictor, this is actually to fix the wrong prediction
io.redirect.valid := valid && isBru && predictWrong
// may be can be moved to ISU to calculate pc + 4
// this is actually for jal and jalr to write pc + 4/2 to rd
io.out.bits := Mux(isBru, Mux(!isRVC, SignExt(io.cfIn.pc, AddrBits) + 4.U, SignExt(io.cfIn.pc, AddrBits) + 2.U), aluRes)
// when(pcPlus2 && isBru){
// printf("CJALR %x %x \n ", io.cfIn.instr, io.cfIn.pc)
// }
Debug(){
when(valid && isBru){
printf("[BRU] tgt %x, valid:%d, npc: %x, pdwrong: %x\n", io.redirect.target, io.redirect.valid, io.cfIn.pnpc, predictWrong)
printf("[BRU] taken:%d addrRes:%x src1:%x src2:%x func:%x\n", taken, adderRes, src1, src2, func)
}
}
Debug(false){
when(valid && isBru){
printf("[BPW] pc %x tgt %x, npc: %x, pdwrong: %x type: %x%x%x%x\n", io.cfIn.pc, io.redirect.target, io.cfIn.pnpc, predictWrong, isBranch, (func === ALUOpType.jal || func === ALUOpType.call), func === ALUOpType.jalr, func === ALUOpType.ret)
}
when(true.B) {
printf("[ALUIN0] valid:%d isBru:%d isBranch:%d \n", valid, isBru, isBranch)
printf("[ALUIN1] pc %x instr %x tgt %x, npc: %x, pdwrong: %x type: %x%x%x%x\n", io.cfIn.pc, io.cfIn.instr, io.redirect.target, io.cfIn.pnpc, predictWrong, isBranch, (func === ALUOpType.jal || func === ALUOpType.call), func === ALUOpType.jalr, func === ALUOpType.ret)
printf("[ALUIN2] func:%b ", func)
printf(" bpuUpdateReq: valid:%d pc:%x isMissPredict:%d actualTarget:%x actualTaken:%x fuOpType:%x btbType:%x isRVC:%d \n", valid && isBru, io.cfIn.pc, predictWrong, target, taken, func, LookupTree(func, RV32I_BRUInstr.bruFuncTobtbTypeTable), isRVC)
printf("[ALUIN3]tgt %x, npc: %x, pdwrong: %x\n", io.redirect.target, io.cfIn.pnpc, predictWrong)
printf("[ALUIN4]taken:%d addrRes:%x src1:%x src2:%x func:%x\n", taken, adderRes, src1, src2, func)
}
}
io.in.ready := true.B
io.out.valid := valid
val bpuUpdateReq = WireInit(0.U.asTypeOf(new BPUUpdateReq))
bpuUpdateReq.valid := valid && isBru
bpuUpdateReq.pc := io.cfIn.pc
bpuUpdateReq.isMissPredict := predictWrong
bpuUpdateReq.actualTarget := target
bpuUpdateReq.actualTaken := taken
bpuUpdateReq.fuOpType := func
bpuUpdateReq.btbType := LookupTree(func, RV32I_BRUInstr.bruFuncTobtbTypeTable)
bpuUpdateReq.isRVC := isRVC
BoringUtils.addSource(RegNext(bpuUpdateReq), "bpuUpdateReq")
val right = valid && isBru && !predictWrong
val wrong = valid && isBru && predictWrong
BoringUtils.addSource(right && isBranch, "MbpBRight")
BoringUtils.addSource(wrong && isBranch, "MbpBWrong")
BoringUtils.addSource(wrong && isBranch && io.cfIn.pc(2,0)==="h0".U && isRVC, "Custom1")
BoringUtils.addSource(wrong && isBranch && io.cfIn.pc(2,0)==="h0".U && !isRVC, "Custom2")
BoringUtils.addSource(wrong && isBranch && io.cfIn.pc(2,0)==="h2".U && isRVC, "Custom3")
BoringUtils.addSource(wrong && isBranch && io.cfIn.pc(2,0)==="h2".U && !isRVC, "Custom4")
BoringUtils.addSource(wrong && isBranch && io.cfIn.pc(2,0)==="h4".U && isRVC, "Custom5")
BoringUtils.addSource(wrong && isBranch && io.cfIn.pc(2,0)==="h4".U && !isRVC, "Custom6")
BoringUtils.addSource(wrong && isBranch && io.cfIn.pc(2,0)==="h6".U && isRVC, "Custom7")
BoringUtils.addSource(wrong && isBranch && io.cfIn.pc(2,0)==="h6".U && !isRVC, "Custom8")
BoringUtils.addSource(right && (func === ALUOpType.jal || func === ALUOpType.call), "MbpJRight")
BoringUtils.addSource(wrong && (func === ALUOpType.jal || func === ALUOpType.call), "MbpJWrong")
BoringUtils.addSource(right && func === ALUOpType.jalr, "MbpIRight")
BoringUtils.addSource(wrong && func === ALUOpType.jalr, "MbpIWrong")
BoringUtils.addSource(right && func === ALUOpType.ret, "MbpRRight")
BoringUtils.addSource(wrong && func === ALUOpType.ret, "MbpRWrong")
}
此差异已折叠。
package noop.fu
import chisel3.{util, _}
import chisel3.util._
import utils._
import noop._
import fpu._
import fpu.FPUIOFunc._
import fpu.divsqrt.DivSqrt
import fpu.fma.FMA
class FpInstr extends NOOPBundle {
val func5 = UInt(5.W)
val fmt = UInt(2.W)
val rs2 = UInt(5.W)
val rs1 = UInt(5.W)
val rm = UInt(3.W)
val rd = UInt(5.W)
val op = UInt(7.W)
assert(this.getWidth == 32)
}
class FpuCsrIO extends NOOPBundle {
val fflags = Output(new Fflags)
val isIllegal = Output(Bool())
val dirty_fs = Output(Bool())
val frm = Input(UInt(3.W))
}
class FPUIO extends FunctionUnitIO{
// use XLEN because fpu share data path with cpu
val src3 = Input(UInt(XLEN.W))
val fpu_csr = new FpuCsrIO
val fpWen = Input(Bool())
val instr = Input(UInt(32.W))
val inputFunc = Input(UInt(1.W))
val outputFunc = Input(UInt(2.W))
}
class FPU extends NOOPModule{
// require(XLEN >= FLEN)
val io = IO(new FPUIO)
val (valid, src1, src2, src3, func) = (io.in.valid, io.in.bits.src1, io.in.bits.src2, io.src3, io.in.bits.func)
def access(valid: Bool, src1: UInt, src2: UInt, src3: UInt, func: UInt): UInt = {
this.valid := valid
this.src1 := src1
this.src2 := src2
this.src3 := src3
this.func := func
io.out.bits
}
val instr = io.instr.asTypeOf(new FpInstr)
val isRVD = instr.fmt(0)
val src = VecInit(Seq(src1, src2, src3)).map(x =>
Mux(io.inputFunc === in_unbox, unboxF64ToF32(x), x)
)
val roudingMode = Mux(instr.rm===7.U, io.fpu_csr.frm, instr.rm)
val op = func(2, 0)
val fu = func(5, 3)
val s_ready :: s_wait :: Nil = Enum(2)
val state = RegInit(s_ready)
switch(state){
is(s_ready){
when(io.in.valid){
state := s_wait
}
}
is(s_wait){
when(io.out.fire()){
state := s_ready
}
}
}
val subModuleInput = Wire(new FPUSubModuleInput)
subModuleInput.a := src(0)
subModuleInput.b := src(1)
subModuleInput.c := src(2)
subModuleInput.op := op
subModuleInput.isDouble := isRVD
subModuleInput.rm := roudingMode
val subModules = Array[FPUSubModule](
Module(new FMA), // 0
Module(new FCMP), // 1
Module(new FMV(XLEN)), // 2
Module(new FloatToInt), // 3
Module(new IntToFloat), // 4
Module(new F32toF64), // 5
Module(new F64toF32), // 6
Module(new DivSqrt) //7
)
val outFuncReg = RegEnable(io.outputFunc, io.in.fire())
val fuReg = RegEnable(fu, io.in.fire())
for((module, idx) <- subModules.zipWithIndex){
module.io.in.bits := subModuleInput
module.io.in.valid := io.in.fire() && idx.U===fu
module.io.out.ready := true.B
}
val subModuleOutput = Wire(Decoupled(new FPUSubModuleOutput))
subModuleOutput := LookupTree(fuReg, subModules.zipWithIndex.map({
case (module, idx) =>
idx.U -> module.io.out
}))
val result = subModuleOutput.bits.result
io.in.ready := state===s_ready
io.out.valid := subModuleOutput.valid
io.out.bits := MuxLookup(outFuncReg, result, Seq(
out_sext -> SignExt(result(31, 0), XLEN),
out_box -> boxF32ToF64(result)
))
//TODO: check illegal rounding mode exception
io.fpu_csr.isIllegal := false.B
io.fpu_csr.dirty_fs := io.in.fire() && io.fpWen
io.fpu_csr.fflags := Mux(io.out.valid, subModuleOutput.bits.fflags, 0.U.asTypeOf(new Fflags))
}
此差异已折叠。
此差异已折叠。
package noop
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import utils._
// memory order unit
object MOUOpType {
def fence = "b00".U
def fencei = "b01".U
def sfence_vma = "b10".U
}
class MOUIO extends FunctionUnitIO {
val cfIn = Flipped(new CtrlFlowIO)
val redirect = new RedirectIO
}
class MOU extends NOOPModule {
val io = IO(new MOUIO)
val (valid, src1, src2, func) = (io.in.valid, io.in.bits.src1, io.in.bits.src2, io.in.bits.func)
def access(valid: Bool, src1: UInt, src2: UInt, func: UInt): UInt = {
this.valid := valid
this.src1 := src1
this.src2 := src2
this.func := func
io.out.bits
}
io.redirect.target := io.cfIn.pc + 4.U
io.redirect.valid := valid
val flushICache = valid && (func === MOUOpType.fencei)
BoringUtils.addSource(flushICache, "MOUFlushICache")
Debug(false){
when(flushICache){
printf("%d: [MOU] Flush I$ at %x\n", GTimer(), io.cfIn.pc)
}
}
val flushTLB = valid && (func === MOUOpType.sfence_vma)
BoringUtils.addSource(flushTLB, "MOUFlushTLB")
Debug(false) {
when (flushTLB) {
printf("%d: [MOU] Flush TLB at %x\n", GTimer(), io.cfIn.pc)
}
}
io.out.bits := 0.U
io.in.ready := true.B
io.out.valid := valid
}
package noop
import chisel3._
import chisel3.util._
object Priviledged extends HasInstrType {
def ECALL = BitPat("b000000000000_00000_000_00000_1110011")
def MRET = BitPat("b001100000010_00000_000_00000_1110011")
def SRET = BitPat("b000100000010_00000_000_00000_1110011")
def SFANCE_VMA = BitPat("b0001001_?????_?????_000_00000_1110011")
def FENCE = BitPat("b????????????_?????_000_?????_0001111")
def WFI = BitPat("b0001000_00101_00000_000_00000_1110011")
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)
)
}
package noop
import chisel3._
import chisel3.util._
object RVAInstr extends HasInstrType {
// Note: use instr(14,12) to distinguish D/W inst
// def LR = BitPat("b00010??00000_?????_???_?????_0101111")
// def SC = BitPat("b00011??00000_?????_???_?????_0101111")
def LR_D = BitPat("b00010_??_00000_?????_011_?????_0101111")
def SC_D = BitPat("b00011_??_?????_?????_011_?????_0101111")
def LR_W = BitPat("b00010_??_00000_?????_010_?????_0101111")
def SC_W = BitPat("b00011_??_?????_?????_010_?????_0101111")
def AMOSWAP = BitPat("b00001_??_?????_?????_01?_?????_0101111")
def AMOADD = BitPat("b00000_??_?????_?????_01?_?????_0101111")
def AMOXOR = BitPat("b00100_??_?????_?????_01?_?????_0101111")
def AMOAND = BitPat("b01100_??_?????_?????_01?_?????_0101111")
def AMOOR = BitPat("b01000_??_?????_?????_01?_?????_0101111")
def AMOMIN = BitPat("b10000_??_?????_?????_01?_?????_0101111")
def AMOMAX = BitPat("b10100_??_?????_?????_01?_?????_0101111")
def AMOMINU = BitPat("b11000_??_?????_?????_01?_?????_0101111")
def AMOMAXU = BitPat("b11100_??_?????_?????_01?_?????_0101111")
// funct3 === 010 or 011
val table = Array(
// LR -> List(InstrI, FuType.lsu, LSUOpType.lr),
LR_D -> List(InstrI, FuType.lsu, LSUOpType.lr),
LR_W -> List(InstrI, FuType.lsu, LSUOpType.lr),
// SC -> List(InstrS, FuType.lsu, LSUOpType.sc),
SC_D -> List(InstrSA, FuType.lsu, LSUOpType.sc),
SC_W -> List(InstrSA, FuType.lsu, LSUOpType.sc),
AMOSWAP -> List(InstrR, FuType.lsu, LSUOpType.amoswap),
AMOADD -> List(InstrR, FuType.lsu, LSUOpType.amoadd),
AMOXOR -> List(InstrR, FuType.lsu, LSUOpType.amoxor),
AMOAND -> List(InstrR, FuType.lsu, LSUOpType.amoand),
AMOOR -> List(InstrR, FuType.lsu, LSUOpType.amoor),
AMOMIN -> List(InstrR, FuType.lsu, LSUOpType.amomin),
AMOMAX -> List(InstrR, FuType.lsu, LSUOpType.amomax),
AMOMINU -> List(InstrR, FuType.lsu, LSUOpType.amominu),
AMOMAXU -> List(InstrR, FuType.lsu, LSUOpType.amomaxu)
)
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
package noop
import chisel3._
import chisel3.util._
object RVZicsrInstr extends HasInstrType {
def CSRRW = BitPat("b????????????_?????_001_?????_1110011")
def CSRRS = BitPat("b????????????_?????_010_?????_1110011")
def CSRRC = BitPat("b????????????_?????_011_?????_1110011")
def CSRRWI = BitPat("b????????????_?????_101_?????_1110011")
def CSRRSI = BitPat("b????????????_?????_110_?????_1110011")
def CSRRCI = BitPat("b????????????_?????_111_?????_1110011")
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)
)
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册