├── .github └── workflows │ └── main.yml ├── .gitignore ├── .gitmodules ├── .mill-version ├── LICENSE ├── Makefile ├── README.md ├── build.sc ├── debian_on_fpga.gif ├── debug ├── .gitignore ├── Makefile └── perftest.sh ├── env.sh ├── fpga ├── Makefile ├── Makefile.check ├── NutShell.tcl ├── board │ ├── PXIe │ │ ├── bd │ │ │ └── arm.tcl │ │ ├── constr │ │ │ └── pcie.xdc │ │ ├── mk.tcl │ │ └── rtl │ │ │ ├── addr_mapper.v │ │ │ └── system_top.v │ ├── axu3cg │ │ ├── bd │ │ │ └── arm.tcl │ │ ├── constr │ │ │ └── hdmi.xdc │ │ ├── mk.tcl │ │ └── rtl │ │ │ ├── addr_mapper.v │ │ │ ├── hdmi │ │ │ ├── i2c_config.v │ │ │ ├── i2c_master_bit_ctrl.v │ │ │ ├── i2c_master_byte_ctrl.v │ │ │ ├── i2c_master_defines.v │ │ │ ├── i2c_master_top.v │ │ │ └── timescale.v │ │ │ └── system_top.v │ ├── common.tcl │ └── pynq │ │ ├── bd │ │ └── standalone.tcl │ │ └── mk.tcl ├── boot │ ├── .gitignore │ ├── README.md │ ├── axu3cg │ │ └── u-boot.elf │ ├── bootgen-zynq-standalone.bif │ ├── bootgen-zynq.bif │ ├── bootgen-zynqmp.bif │ ├── bug-list.md │ ├── mk.tcl │ ├── pynq │ │ ├── BOOT.BIN │ │ └── RV_BOOT.bin │ └── standalone.md ├── lib │ └── include │ │ └── axi.vh └── resource │ ├── ddr-loader │ └── ddr-loader.c │ └── fsbl-loader │ ├── .gitignore │ ├── Makefile │ ├── fsbl-loader.c │ └── lscript.ld ├── ready-to-run ├── linux.bin ├── microbench.bin └── riscv64-nemu-interpreter-so ├── scalastyle-config.xml ├── scalastyle-test-config.xml ├── scripts └── statistics.py ├── src ├── main │ └── scala │ │ ├── bus │ │ ├── axi4 │ │ │ ├── AXI4.scala │ │ │ └── Delayer.scala │ │ ├── memport │ │ │ └── MemPort.scala │ │ └── simplebus │ │ │ ├── AddressMapper.scala │ │ │ ├── Crossbar.scala │ │ │ ├── DistributedMem.scala │ │ │ ├── SimpleBus.scala │ │ │ ├── ToAXI4.scala │ │ │ └── ToMemPort.scala │ │ ├── device │ │ ├── AXI4CLINT.scala │ │ ├── AXI4DMA.scala │ │ ├── AXI4DummySD.scala │ │ ├── AXI4Flash.scala │ │ ├── AXI4Keyboard.scala │ │ ├── AXI4PLIC.scala │ │ ├── AXI4RAM.scala │ │ ├── AXI4Slave.scala │ │ ├── AXI4UART.scala │ │ └── AXI4VGA.scala │ │ ├── nutcore │ │ ├── Bundle.scala │ │ ├── Decode.scala │ │ ├── NutCore.scala │ │ ├── NutCoreTrap.scala │ │ ├── RF.scala │ │ ├── backend │ │ │ ├── fu │ │ │ │ ├── ALU.scala │ │ │ │ ├── CSR.scala │ │ │ │ ├── LSU.scala │ │ │ │ ├── MDU.scala │ │ │ │ ├── MOU.scala │ │ │ │ └── UnpipelinedLSU.scala │ │ │ ├── ooo │ │ │ │ ├── Backend.scala │ │ │ │ ├── EP.scala │ │ │ │ ├── ROB.scala │ │ │ │ └── RS.scala │ │ │ └── seq │ │ │ │ ├── EXU.scala │ │ │ │ ├── ISU.scala │ │ │ │ └── WBU.scala │ │ ├── frontend │ │ │ ├── BPU.scala │ │ │ ├── Frontend.scala │ │ │ ├── IBF.scala │ │ │ ├── IDU.scala │ │ │ ├── IFU.scala │ │ │ └── NaiveIBF.scala │ │ ├── isa │ │ │ ├── Privileged.scala │ │ │ ├── RVA.scala │ │ │ ├── RVC.scala │ │ │ ├── RVI.scala │ │ │ ├── RVM.scala │ │ │ ├── RVZicsr.scala │ │ │ ├── RVZifencei.scala │ │ │ └── predecode │ │ │ │ └── predecode.scala │ │ ├── mem │ │ │ ├── Cache.scala │ │ │ ├── EmbeddedTLB.scala │ │ │ └── TLB.scala │ │ └── utils │ │ │ └── WritebackDelayer.scala │ │ ├── sim │ │ ├── MeipGen.scala │ │ ├── NutShellSim.scala │ │ └── SimMMIO.scala │ │ ├── system │ │ ├── Coherence.scala │ │ ├── NutShell.scala │ │ └── Prefetcher.scala │ │ ├── top │ │ └── Settings.scala │ │ └── utils │ │ ├── BitUtils.scala │ │ ├── Debug.scala │ │ ├── FlushableQueue.scala │ │ ├── GTimer.scala │ │ ├── Hold.scala │ │ ├── LFSR64.scala │ │ ├── LatencyPipe.scala │ │ ├── Lock.scala │ │ ├── LookupTree.scala │ │ ├── Pipeline.scala │ │ ├── PipelineVector.scala │ │ ├── RegMap.scala │ │ ├── SRAMTemplate.scala │ │ └── StopWatch.scala └── test │ ├── scala │ └── TopMain.scala │ └── testcase │ ├── Makefile │ ├── include │ └── runtime.h │ └── tests │ ├── dma.c │ └── plic.c └── tools └── readmemh ├── Makefile ├── gen-treadle-readmemh.c ├── groupby-4byte.c └── split-readmemh.c /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | # Controls when the workflow will run 4 | on: 5 | # Triggers the workflow on push or pull request events but only for the master branch 6 | push: 7 | branches: [ master ] 8 | pull_request: 9 | branches: [ master ] 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 15 | jobs: 16 | test-nutshell: 17 | # The type of runner that the job will run on 18 | runs-on: ubuntu-22.04 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | 23 | - name: Prepare environment 24 | run: | 25 | cd $GITHUB_WORKSPACE/.. 26 | git config --global url."https://github.com/".insteadOf git@github.com: 27 | git config --global url."https://".insteadOf git:// 28 | git clone https://github.com/OpenXiangShan/xs-env 29 | cd $GITHUB_WORKSPACE/../xs-env 30 | sudo -s ./setup-tools.sh 31 | source ./setup.sh 32 | rm -r $GITHUB_WORKSPACE/../xs-env/NutShell 33 | cp -r $GITHUB_WORKSPACE $GITHUB_WORKSPACE/../xs-env 34 | cd $GITHUB_WORKSPACE/../xs-env 35 | source ./env.sh 36 | cd $GITHUB_WORKSPACE/../xs-env/NutShell 37 | source ./env.sh 38 | make init 39 | 40 | - name: Generate Verilog 41 | run: | 42 | cd $GITHUB_WORKSPACE/../xs-env 43 | source ./env.sh 44 | cd $GITHUB_WORKSPACE/../xs-env/NutShell 45 | source ./env.sh 46 | make clean 47 | make verilog 48 | - name: Generate Verilog for FPGA 49 | run: | 50 | cd $GITHUB_WORKSPACE/../xs-env 51 | source ./env.sh 52 | cd $GITHUB_WORKSPACE/../xs-env/NutShell 53 | source ./env.sh 54 | make clean 55 | make verilog BOARD=pynq 56 | 57 | - name: Microbench - Nutshell 58 | run: | 59 | cd $GITHUB_WORKSPACE/../xs-env 60 | source ./env.sh 61 | cd $GITHUB_WORKSPACE/../xs-env/NutShell 62 | source ./env.sh 63 | make clean 64 | make emu 65 | ./build/emu -b 0 -e 0 -i ./ready-to-run/microbench.bin --diff ./ready-to-run/riscv64-nemu-interpreter-so 66 | 67 | - name: Linux - Nutshell 68 | run: | 69 | cd $GITHUB_WORKSPACE/../xs-env 70 | source ./env.sh 71 | cd $GITHUB_WORKSPACE/../xs-env/NutShell 72 | source ./env.sh 73 | make clean 74 | make emu 75 | ./build/emu -b 0 -e 0 -i ./ready-to-run/linux.bin -C 200000000 --diff ./ready-to-run/riscv64-nemu-interpreter-so 76 | 77 | # - name: Microbench - Argo 78 | # run: | 79 | # cd $GITHUB_WORKSPACE/../xs-env 80 | # source ./env.sh 81 | # cd $GITHUB_WORKSPACE/../xs-env/NutShell 82 | # source ./env.sh 83 | # make clean 84 | # make emu CORE=ooo EMU_CXX_EXTRA_FLAGS="-DFIRST_INST_ADDRESS=0x80000000" 85 | # ./build/emu -b 0 -e 0 -i ./ready-to-run/microbench.bin 86 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "difftest"] 2 | path = difftest 3 | url = https://github.com/OpenXiangShan/difftest.git 4 | 5 | -------------------------------------------------------------------------------- /.mill-version: -------------------------------------------------------------------------------- 1 | 0.11.7 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TOP = TopMain 2 | SIM_TOP = SimTop 3 | FPGATOP = Top 4 | REAL_TOP = $(if $(strip $(subst sim,,$(BOARD))),$(FPGATOP),$(SIM_TOP)) 5 | 6 | BUILD_DIR = $(abspath ./build) 7 | 8 | RTL_DIR = $(BUILD_DIR)/rtl 9 | RTL_SUFFIX ?= sv 10 | SIM_TOP_V = $(RTL_DIR)/$(REAL_TOP).$(RTL_SUFFIX) # if use FPGA, use FPGATOP 11 | TOP_V = $(RTL_DIR)/$(TOP).$(RTL_SUFFIX) 12 | 13 | SCALA_FILE = $(shell find ./src/main/scala -name '*.scala') 14 | TEST_FILE = $(shell find ./src/test/scala -name '*.scala') 15 | 16 | USE_READY_TO_RUN_NEMU = true 17 | 18 | SIMTOP = top.TopMain 19 | IMAGE ?= ready-to-run/linux.bin 20 | 21 | DATAWIDTH ?= 64 22 | BOARD ?= sim # sim pynq axu3cg 23 | CORE ?= inorder # inorder ooo embedded 24 | 25 | MILL_ARGS_ALL = $(MILL_ARGS) 26 | MILL_ARGS_ALL += --target-dir $(RTL_DIR) BOARD=$(BOARD) CORE=$(CORE) 27 | FPGA_ARGS = 28 | 29 | ifneq ($(FIRTOOL),) 30 | MILL_ARGS_ALL += --firtool-binary-path $(FIRTOOL) 31 | endif 32 | 33 | MILL_ARGS_ALL += --split-verilog 34 | 35 | .DEFAULT_GOAL = verilog 36 | 37 | help: 38 | mill -i generator.test.runMain top.$(TOP) --help $(MILL_ARGS_ALL) 39 | 40 | $(TOP_V): $(SCALA_FILE) 41 | mkdir -p $(@D) 42 | mill -i generator.test.runMain top.$(TOP) $(MILL_ARGS_ALL) $(FPGA_ARGS) 43 | @mv $(SIM_TOP_V) $(TOP_V) 44 | @for file in $(RTL_DIR)/*.$(RTL_SUFFIX); do \ 45 | sed -i -e 's/_\(aw\|ar\|w\|r\|b\)_\(\|bits_\)/_\1/g' "$$file"; \ 46 | done 47 | @git log -n 1 >> .__head__ 48 | @git diff >> .__diff__ 49 | @sed -i 's/^/\/\// ' .__head__ 50 | @sed -i 's/^/\/\//' .__diff__ 51 | @cat .__head__ .__diff__ $@ > .__out__ 52 | @mv .__out__ $@ 53 | @rm .__head__ .__diff__ 54 | 55 | deploy: build/top.zip 56 | 57 | 58 | build/top.zip: $(TOP_V) 59 | @zip -r $@ $< $<.conf build/*.anno.json 60 | 61 | .PHONY: deploy build/top.zip 62 | 63 | verilog: $(TOP_V) 64 | 65 | $(SIM_TOP_V): $(SCALA_FILE) $(TEST_FILE) 66 | mkdir -p $(@D) 67 | mill -i generator.test.runMain $(SIMTOP) $(MILL_ARGS_ALL) 68 | @for file in $(RTL_DIR)/*.$(RTL_SUFFIX); do \ 69 | sed -i -e 's/$$fatal/xs_assert_v2(`__FILE__, `__LINE__)/g' "$$file"; \ 70 | sed -i -e "s/\$$error(/\$$fwrite(32\'h80000002, /g" "$$file"; \ 71 | done 72 | 73 | sim-verilog: $(SIM_TOP_V) 74 | 75 | emu: sim-verilog 76 | $(MAKE) -C ./difftest emu WITH_CHISELDB=0 WITH_CONSTANTIN=0 RTL_SUFFIX=$(RTL_SUFFIX) 77 | 78 | emu-run: sim-verilog 79 | $(MAKE) -C ./difftest emu-run RTL_SUFFIX=$(RTL_SUFFIX) 80 | 81 | simv: sim-verilog 82 | $(MAKE) -C ./difftest simv WITH_CHISELDB=0 WITH_CONSTANTIN=0 RTL_SUFFIX=$(RTL_SUFFIX) 83 | 84 | init: 85 | git submodule update --init 86 | 87 | clean: 88 | rm -rf $(BUILD_DIR) 89 | 90 | bsp: 91 | mill -i mill.bsp.BSP/install 92 | 93 | idea: 94 | mill -i mill.idea.GenIdea/idea 95 | 96 | .PHONY: verilog emu clean help $(REF_SO) 97 | -------------------------------------------------------------------------------- /build.sc: -------------------------------------------------------------------------------- 1 | import mill._, scalalib._ 2 | import coursier.maven.MavenRepository 3 | 4 | object ivys { 5 | val scala = "2.13.14" 6 | val chisel = ivy"org.chipsalliance::chisel:6.5.0" 7 | val chiselPlugin = ivy"org.chipsalliance:::chisel-plugin:6.5.0" 8 | } 9 | 10 | trait CommonModule extends ScalaModule { 11 | override def scalaVersion = ivys.scala 12 | 13 | override def scalacOptions = Seq("-Ymacro-annotations") 14 | } 15 | 16 | trait HasChisel extends ScalaModule { 17 | override def ivyDeps = Agg(ivys.chisel) 18 | override def scalacPluginIvyDeps = Agg(ivys.chiselPlugin) 19 | } 20 | 21 | trait CommonNS extends SbtModule with CommonModule with HasChisel 22 | 23 | object difftest extends CommonNS { 24 | override def millSourcePath = os.pwd / "difftest" 25 | } 26 | 27 | object generator extends CommonNS { 28 | 29 | override def millSourcePath = os.pwd 30 | 31 | override def moduleDeps = super.moduleDeps ++ Seq( 32 | difftest 33 | ) 34 | 35 | object test extends SbtModuleTests with TestModule.ScalaTest 36 | 37 | } 38 | -------------------------------------------------------------------------------- /debian_on_fpga.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OSCPU/NutShell/fc12171d929e7e589fab9f794ab63ce12e6c594e/debian_on_fpga.gif -------------------------------------------------------------------------------- /debug/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | -------------------------------------------------------------------------------- /debug/Makefile: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------ 2 | # test settings 3 | # ------------------------------------------------------------------ 4 | 5 | LOG_BEGIN ?= 0 6 | LOG_END ?= 0 7 | 8 | ARCH = ARCH=riscv64-nutshell 9 | # ------------------------------------------------------------------ 10 | 11 | SINGLETEST = recursion 12 | RVTEST_TARGET = towers 13 | NANOS_HOME ?= $(AM_HOME)/../nanos-lite 14 | EMU_ARGS = B=$(LOG_BEGIN) E=$(LOG_END) 15 | CPU_TEST_RESULT = $(shell cat cpu.log | grep -E "different|stuck") 16 | MB_RESULT = $(shell cat microbench.log | grep IPC) 17 | MBT_RESULT = $(shell cat microbench-train.log | grep IPC) 18 | CM_RESULT = $(shell cat coremark.log | grep IPC) 19 | 20 | # ------------------------------------------------------------------ 21 | # bulid CPU and run dummy test 22 | # ------------------------------------------------------------------ 23 | 24 | cpu: 25 | $(MAKE) -C $(AM_HOME)/tests/cputest $(ARCH) $(EMU_ARGS) ALL=dummy run 26 | 27 | # ------------------------------------------------------------------ 28 | # unit tests 29 | # ------------------------------------------------------------------ 30 | 31 | cputest: 32 | $(MAKE) -C $(AM_HOME)/tests/cputest $(ARCH) $(EMU_ARGS) run 2>&1 | tee > cpu.log 33 | # cat cpu.log | grep different 34 | ifeq ($(CPU_TEST_RESULT),) 35 | @echo "simple CPU test passed" 36 | else 37 | @echo $(CPU_TEST_RESULT) 38 | @echo "simple CPU test failed" 39 | endif 40 | 41 | rvtest-ui: 42 | $(MAKE) -C $(RVTEST_HOME)/isa noop_run LOG_LEVEL=OFF SUITES=rv64ui ENV=p 43 | 44 | rvtest: 45 | $(MAKE) -C $(RVTEST_HOME)/isa noop_run LOG_LEVEL=OFF SUITES=rv64ui ENV=p 46 | $(MAKE) -C $(RVTEST_HOME)/isa noop_run LOG_LEVEL=OFF SUITES=rv64um ENV=p 47 | $(MAKE) -C $(RVTEST_HOME)/isa noop_run LOG_LEVEL=OFF SUITES=rv64uc ENV=p 48 | $(MAKE) -C $(RVTEST_HOME)/isa noop_run LOG_LEVEL=OFF SUITES=rv64si ENV=p 49 | $(MAKE) -C $(RVTEST_HOME)/isa noop_run LOG_LEVEL=OFF SUITES=rv64mi ENV=p 50 | 51 | bputest: 52 | $(MAKE) -C $(AM_HOME)/tests/bputest $(ARCH) $(EMU_ARGS) ALL=forcall2 run 2>&1 | tee > bpu.log 53 | cat bpu.log | grep Mbp 54 | 55 | unittest: 56 | $(MAKE) -C $(AM_HOME)/tests/cputest $(ARCH) $(EMU_ARGS) ALL=$(SINGLETEST) run 2>&1 | tee > test.log 57 | cat test.log | grep -E "different|stuck|GOOD" 58 | cat test.log | grep ISU > isu.log 59 | 60 | microbench: 61 | $(MAKE) -C $(AM_HOME)/apps/microbench $(ARCH) $(EMU_ARGS) mainargs=test run 2>&1 | tee > microbench.log 62 | cat microbench.log | grep IPC 63 | @date >> history.log 64 | @git log --pretty=format:"%h %an %ad %s" -1 >> history.log 65 | @echo -e "" >> history.log 66 | @echo $(MB_RESULT) >> history.log 67 | @echo -e "" >> history.log 68 | 69 | microbench-train: 70 | $(MAKE) -C $(AM_HOME)/apps/microbench $(ARCH) $(EMU_ARGS) mainargs=train run 2>&1 | tee > microbench-train.log 71 | cat microbench-train.log | grep IPC 72 | 73 | coremark: 74 | $(MAKE) -C $(AM_HOME)/apps/coremark $(ARCH) $(EMU_ARGS) mainargs=test run 2>&1 | tee > coremark.log 75 | cat coremark.log | grep IPC 76 | @date >> cm_history.log 77 | @git log --pretty=format:"%h %an %ad %s" -1 >> cm_history.log 78 | @echo -e "" >> cm_history.log 79 | @echo $(CM_RESULT) >> cm_history.log 80 | @echo -e "" >> cm_history.log 81 | 82 | 83 | dhrystone: 84 | $(MAKE) -C $(AM_HOME)/apps/dhrystone $(ARCH) $(EMU_ARGS) mainargs=test run 2>&1 | tee > dhrystone.log 85 | cat dhrystone.log | grep IPC 86 | 87 | xj: 88 | $(MAKE) -C $(NANOS_HOME) $(ARCH) $(EMU_ARGS) run 89 | 90 | xjnemu: 91 | $(MAKE) -C $(NANOS_HOME) ARCH=riscv64-nemu run 92 | 93 | rttos: 94 | $(MAKE) -C $(RTTOS_HOME)/bsp/riscv64-nutshell run 95 | 96 | rttos-debug: 97 | $(MAKE) -C $(RTTOS_HOME)/bsp/riscv64-nutshell run 2>&1 | tee > rttos.log 98 | 99 | freertos: 100 | $(MAKE) -C $(FREERTOS_HOME)/Demo/riscv64-nutshell nutshell_run 101 | 102 | xv6: 103 | $(MAKE) -C $(XV6_HOME) nutshell 104 | 105 | xv6-debug: 106 | $(MAKE) -C $(XV6_HOME) nutshell 2>&1 | tee > xv6.log 107 | 108 | linux: 109 | $(MAKE) -C $(BBL_LINUX_HOME) nutshell 110 | 111 | linux-debug: 112 | $(MAKE) -C $(BBL_LINUX_HOME) nutshell 2>&1 | tee > linux.log 113 | 114 | # ------------------------------------------------------------------ 115 | # test set 116 | # ------------------------------------------------------------------ 117 | 118 | smoke-test: cpu cputest microbench coremark 119 | @echo "Smoke Test Passed" 120 | 121 | regression-test: smoke-test coremark linux 122 | @echo "Regression Test Passed" 123 | 124 | perf-test: smoke-test microbench-train 125 | @echo "Perf Test Finished" 126 | 127 | # ------------------------------------------------------------------ 128 | # get disassembled test src 129 | # ------------------------------------------------------------------ 130 | 131 | disassemble-unittest: 132 | cp $(AM_HOME)/tests/cputest/build/$(SINGLETEST)-riscv64-noop.txt ./d-unittest.log 133 | 134 | disassemble-rttos: 135 | cp $(RTTOS_HOME)/bsp/riscv64-nutshell/build/code.txt ./d-rttos.log 136 | 137 | disassemble-freertos: 138 | cp $(FREERTOS_HOME)/Demo/riscv64-nutshell/build/FreeRTOS-simple.elf.txt ./d-freertos.log 139 | 140 | disassemble-xv6: 141 | cp $(XV6_HOME)/build/code.txt ./d-xv6.log 142 | 143 | # ------------------------------------------------------------------ 144 | # chore 145 | # ------------------------------------------------------------------ 146 | 147 | clean: 148 | $(MAKE) -C .. clean -------------------------------------------------------------------------------- /debug/perftest.sh: -------------------------------------------------------------------------------- 1 | echo run all benchmarks: 2 | echo median 3 | make rvtest RVTEST_TARGET=median 2>&1 | tee > median.log 4 | echo multiply 5 | make rvtest RVTEST_TARGET=multiply 2>&1 | tee > multiply.log 6 | echo qsort 7 | make rvtest RVTEST_TARGET=qsort 2>&1 | tee > qsort.log 8 | echo rsort 9 | make rvtest RVTEST_TARGET=rsort 2>&1 | tee > rsort.log 10 | echo towers 11 | make rvtest RVTEST_TARGET=towers 2>&1 | tee > towers.log 12 | echo vvadd 13 | make rvtest RVTEST_TARGET=vvadd 2>&1 | tee > vvadd.log 14 | echo smoke-test 15 | make smoke-test 16 | echo coremark 17 | make coremark 18 | echo dhrystone 19 | make dhrystone 20 | echo microbench-train 21 | make microbench-train -------------------------------------------------------------------------------- /env.sh: -------------------------------------------------------------------------------- 1 | export NOOP_HOME=$(pwd) -------------------------------------------------------------------------------- /fpga/Makefile: -------------------------------------------------------------------------------- 1 | include Makefile.check 2 | 3 | default: project 4 | 5 | STANDALONE ?= false 6 | 7 | # vivado project name 8 | PRJ ?= myproject 9 | PRJ_FULL = $(PRJ)-$(BOARD) 10 | VIVADO_FLAG = -nolog -nojournal -notrace 11 | 12 | #-------------------------------------------------------------------- 13 | # Project building and implementation 14 | #-------------------------------------------------------------------- 15 | 16 | PRJ_ROOT = board/$(BOARD)/build/$(PRJ_FULL) 17 | XPR_FILE = $(PRJ_ROOT)/$(PRJ_FULL).xpr 18 | $(XPR_FILE): 19 | make -C .. BOARD=$(BOARD) 20 | vivado $(VIVADO_FLAG) -mode batch -source board/$(BOARD)/mk.tcl -tclargs $(PRJ_FULL) $(STANDALONE) 21 | 22 | project: $(XPR_FILE) 23 | 24 | bootgen: 25 | cd boot && hsi $(VIVADO_FLAG) -source mk.tcl -tclargs $(PRJ_FULL) $(STANDALONE) 26 | 27 | vivado: $(XPR_FILE) 28 | vivado $(VIVADO_FLAG) $(XPR_FILE) & 29 | 30 | .PHONY: default project vivado bootgen 31 | -------------------------------------------------------------------------------- /fpga/Makefile.check: -------------------------------------------------------------------------------- 1 | ifneq ($(MAKECMDGOALS),clean) # ignore check for make clean 2 | 3 | BOARD ?= zedboard 4 | 5 | BOARDS = $(shell ls board/) 6 | 7 | ifeq ($(filter $(BOARDS), $(BOARD)), ) # BOARD must be valid 8 | $(error Invalid BOARD. Supported: $(BOARDS)) 9 | endif 10 | 11 | endif 12 | -------------------------------------------------------------------------------- /fpga/board/PXIe/constr/pcie.xdc: -------------------------------------------------------------------------------- 1 | create_clock -period 10.000 -name pcie_x86_refclk -waveform {0.000 5.000} [get_ports CLK_IN_D_clk_p] 2 | set_property PACKAGE_PIN AB35 [get_ports {CLK_IN_D_clk_n[0]}] 3 | set_property PACKAGE_PIN AB34 [get_ports {CLK_IN_D_clk_p[0]}] 4 | 5 | set_property PACKAGE_PIN W41 [get_ports {pcie_mgt_rxp[0]}] 6 | set_property PACKAGE_PIN W42 [get_ports {pcie_mgt_rxn[0]}] 7 | set_property PACKAGE_PIN Y34 [get_ports {pcie_mgt_txp[0]}] 8 | set_property PACKAGE_PIN Y35 [get_ports {pcie_mgt_txn[0]}] 9 | -------------------------------------------------------------------------------- /fpga/board/PXIe/mk.tcl: -------------------------------------------------------------------------------- 1 | set device xczu19eg-ffvc1760-2-i 2 | 3 | set script_dir [file dirname [info script]] 4 | 5 | # Add files for system top 6 | set src_files [list \ 7 | "[file normalize "${script_dir}/rtl/system_top.v"]" \ 8 | "[file normalize "${script_dir}/rtl/addr_mapper.v"]" \ 9 | ] 10 | 11 | # Add files for constraint 12 | set xdc_files [list \ 13 | "[file normalize "${script_dir}/constr/pcie.xdc"]" \ 14 | ] 15 | 16 | source ${script_dir}/../common.tcl 17 | -------------------------------------------------------------------------------- /fpga/board/PXIe/rtl/addr_mapper.v: -------------------------------------------------------------------------------- 1 | module addr_mapper ( 2 | `axi_slave_if(s_axi, 64, 8), 3 | `axi_master_if(m_axi, 64, 8) 4 | ); 5 | 6 | assign m_axi_awaddr = {4'd8, 1'b0, s_axi_awaddr[30:0]}; 7 | assign m_axi_araddr = {4'd8, 1'b0, s_axi_araddr[30:0]}; 8 | assign m_axi_arburst = s_axi_arburst; 9 | assign m_axi_arcache = s_axi_arcache; 10 | assign m_axi_arid = s_axi_arid ; 11 | // assign m_axi_aruser = s_axi_aruser ; 12 | assign m_axi_arlen = s_axi_arlen ; 13 | assign m_axi_arlock = s_axi_arlock ; 14 | assign m_axi_arprot = s_axi_arprot ; 15 | assign s_axi_arready = m_axi_arready; 16 | assign m_axi_arsize = s_axi_arsize ; 17 | assign m_axi_arvalid = s_axi_arvalid; 18 | assign m_axi_awburst = s_axi_awburst; 19 | assign m_axi_awcache = s_axi_awcache; 20 | assign m_axi_awid = s_axi_awid ; 21 | // assign m_axi_awuser = s_axi_awuser ; 22 | assign m_axi_awlen = s_axi_awlen ; 23 | assign m_axi_awlock = s_axi_awlock ; 24 | assign m_axi_awprot = s_axi_awprot ; 25 | assign s_axi_awready = m_axi_awready; 26 | assign m_axi_awsize = s_axi_awsize ; 27 | assign m_axi_awvalid = s_axi_awvalid; 28 | assign s_axi_bid = m_axi_bid ; 29 | assign m_axi_bready = s_axi_bready ; 30 | assign s_axi_bresp = m_axi_bresp ; 31 | assign s_axi_bvalid = m_axi_bvalid ; 32 | assign s_axi_rdata = m_axi_rdata ; 33 | assign s_axi_rid = m_axi_rid ; 34 | assign s_axi_rlast = m_axi_rlast ; 35 | assign m_axi_rready = s_axi_rready ; 36 | assign s_axi_rresp = m_axi_rresp ; 37 | assign s_axi_rvalid = m_axi_rvalid ; 38 | assign m_axi_wdata = s_axi_wdata ; 39 | assign m_axi_wlast = s_axi_wlast ; 40 | assign s_axi_wready = m_axi_wready ; 41 | assign m_axi_wstrb = s_axi_wstrb ; 42 | assign m_axi_wvalid = s_axi_wvalid ; 43 | assign m_axi_arqos = s_axi_arqos ; 44 | assign m_axi_awqos = s_axi_awqos ; 45 | 46 | endmodule 47 | -------------------------------------------------------------------------------- /fpga/board/PXIe/rtl/system_top.v: -------------------------------------------------------------------------------- 1 | `include "axi.vh" 2 | 3 | module system_top ( 4 | input [0:0]CLK_IN_D_clk_n, 5 | input [0:0]CLK_IN_D_clk_p, 6 | input [0:0]pcie_mgt_rxn, 7 | input [0:0]pcie_mgt_rxp, 8 | output [0:0]pcie_mgt_txn, 9 | output [0:0]pcie_mgt_txp 10 | //output [7:0] led 11 | ); 12 | 13 | `axi_wire(AXI_MEM_MAPPED, 64, 8); 14 | `axi_wire(AXI_MEM, 64, 8); 15 | `axi_wire(AXI_MMIO, 64, 8); 16 | `axi_wire(AXI_DMA, 64, 16); 17 | 18 | wire coreclk; 19 | wire corerstn; 20 | wire uncoreclk; 21 | wire uncorerstn; 22 | 23 | wire [4:0] intrs; 24 | 25 | wire nutshell_uart_tx; 26 | wire nutshell_uart_rx; 27 | 28 | zynq_soc zynq_soc_i ( 29 | `axi_connect_if(AXI_MEM, AXI_MEM_MAPPED), 30 | `axi_connect_if(AXI_MMIO, AXI_MMIO), 31 | `axi_connect_if(AXI_DMA, AXI_DMA), 32 | 33 | .CLK_IN_D_clk_n(CLK_IN_D_clk_n), 34 | .CLK_IN_D_clk_p(CLK_IN_D_clk_p), 35 | .pcie_mgt_rxn(pcie_mgt_rxn), 36 | .pcie_mgt_rxp(pcie_mgt_rxp), 37 | .pcie_mgt_txn(pcie_mgt_txn), 38 | .pcie_mgt_txp(pcie_mgt_txp), 39 | 40 | .intrs(intrs), 41 | 42 | .coreclk(coreclk), 43 | .corerstn(corerstn), 44 | .uncoreclk(uncoreclk), 45 | .uncorerstn(uncorerstn) 46 | ); 47 | 48 | addr_mapper addr_mapper_i( 49 | `axi_connect_if(s_axi, AXI_MEM), 50 | `axi_connect_if(m_axi, AXI_MEM_MAPPED) 51 | ); 52 | 53 | reg corerstn_ff; 54 | always@(posedge uncoreclk) begin 55 | corerstn_ff <= corerstn; 56 | end 57 | 58 | reg corerstn_sync[1:0]; 59 | always@(posedge coreclk) begin 60 | corerstn_sync[0] <= corerstn_ff; 61 | corerstn_sync[1] <= corerstn_sync[0]; 62 | end 63 | 64 | nutshell nutshell_i( 65 | `axi_connect_if(AXI_MEM, AXI_MEM), 66 | `axi_connect_if(AXI_DMA, AXI_DMA), 67 | `axi_connect_if_no_id(AXI_MMIO, AXI_MMIO), 68 | 69 | .intrs(intrs), 70 | 71 | .coreclk(coreclk), 72 | .corerstn(corerstn_sync[1]), 73 | .uncoreclk(uncoreclk), 74 | .uncorerstn(uncorerstn) 75 | ); 76 | 77 | endmodule 78 | -------------------------------------------------------------------------------- /fpga/board/axu3cg/constr/hdmi.xdc: -------------------------------------------------------------------------------- 1 | 2 | ############# clock define################## 3 | #set_property PACKAGE_PIN AE5 [get_ports sys_clk] 4 | ##set_property IOSTANDARD LVCMOS18 [get_ports sys_clk] 5 | #set_property IOSTANDARD LVDS [get_ports sys_clk] 6 | ##set_property PACKAGE_PIN AF5 [get_ports sys_clk_n] 7 | ##set_property IOSTANDARD LVCMOS18 [get_ports sys_clk_n] 8 | ########################fan setting######################### 9 | #set_property IOSTANDARD LVCMOS15 [get_ports fan] 10 | #set_property PACKAGE_PIN B5 [get_ports fan] 11 | 12 | #################9134 setting############################## 13 | 14 | # FPGA pin to hdmi signal 15 | set_property PACKAGE_PIN A1 [get_ports hdmi_clk] 16 | set_property PACKAGE_PIN C8 [get_ports {hdmi_rgb[0]}] 17 | set_property PACKAGE_PIN A3 [get_ports {hdmi_rgb[1]}] 18 | set_property PACKAGE_PIN B1 [get_ports {hdmi_rgb[2]}] 19 | set_property PACKAGE_PIN B3 [get_ports {hdmi_rgb[3]}] 20 | set_property PACKAGE_PIN C1 [get_ports {hdmi_rgb[4]}] 21 | set_property PACKAGE_PIN B6 [get_ports {hdmi_rgb[5]}] 22 | set_property PACKAGE_PIN A2 [get_ports {hdmi_rgb[6]}] 23 | set_property PACKAGE_PIN C6 [get_ports {hdmi_rgb[7]}] 24 | set_property PACKAGE_PIN F3 [get_ports {hdmi_rgb[8]}] 25 | set_property PACKAGE_PIN D6 [get_ports {hdmi_rgb[9]}] 26 | set_property PACKAGE_PIN D1 [get_ports {hdmi_rgb[10]}] 27 | set_property PACKAGE_PIN D7 [get_ports {hdmi_rgb[11]}] 28 | set_property PACKAGE_PIN E1 [get_ports {hdmi_rgb[12]}] 29 | set_property PACKAGE_PIN F5 [get_ports {hdmi_rgb[13]}] 30 | set_property PACKAGE_PIN F6 [get_ports {hdmi_rgb[14]}] 31 | set_property PACKAGE_PIN F7 [get_ports {hdmi_rgb[15]}] 32 | set_property PACKAGE_PIN G6 [get_ports {hdmi_rgb[16]}] 33 | set_property PACKAGE_PIN G5 [get_ports {hdmi_rgb[17]}] 34 | set_property PACKAGE_PIN G8 [get_ports {hdmi_rgb[18]}] 35 | set_property PACKAGE_PIN F1 [get_ports {hdmi_rgb[19]}] 36 | set_property PACKAGE_PIN E2 [get_ports {hdmi_rgb[20]}] 37 | set_property PACKAGE_PIN G1 [get_ports {hdmi_rgb[21]}] 38 | set_property PACKAGE_PIN F2 [get_ports {hdmi_rgb[22]}] 39 | set_property PACKAGE_PIN D4 [get_ports {hdmi_rgb[23]}] 40 | set_property PACKAGE_PIN B4 [get_ports hdmi_videovalid] 41 | set_property PACKAGE_PIN B8 [get_ports hdmi_hsync] 42 | set_property PACKAGE_PIN G3 [get_ports hdmi_nreset] 43 | set_property PACKAGE_PIN A4 [get_ports hdmi_vsync] 44 | set_property PACKAGE_PIN E4 [get_ports hdmi_scl] 45 | set_property PACKAGE_PIN E3 [get_ports hdmi_sda] 46 | 47 | set_property IOSTANDARD LVCMOS15 [get_ports hdmi_clk] 48 | set_property IOSTANDARD LVCMOS15 [get_ports {hdmi_rgb[*]}] 49 | set_property IOSTANDARD LVCMOS15 [get_ports hdmi_videovalid] 50 | set_property IOSTANDARD LVCMOS15 [get_ports hdmi_hsync] 51 | set_property IOSTANDARD LVCMOS15 [get_ports hdmi_nreset] 52 | set_property IOSTANDARD LVCMOS15 [get_ports hdmi_vsync] 53 | set_property IOSTANDARD LVCMOS15 [get_ports hdmi_scl] 54 | set_property IOSTANDARD LVCMOS15 [get_ports hdmi_sda] 55 | 56 | set_property SLEW FAST [get_ports {hdmi_rgb[*]}] 57 | set_property SLEW FAST [get_ports hdmi_videovalid] 58 | set_property SLEW FAST [get_ports hdmi_hsync] 59 | set_property SLEW FAST [get_ports hdmi_vsync] 60 | -------------------------------------------------------------------------------- /fpga/board/axu3cg/mk.tcl: -------------------------------------------------------------------------------- 1 | set device xczu3cg-sfvc784-1-e 2 | 3 | set script_dir [file dirname [info script]] 4 | 5 | # Add files for system top 6 | set src_files [list \ 7 | "[file normalize "${script_dir}/rtl/system_top.v"]" \ 8 | "[file normalize "${script_dir}/rtl/addr_mapper.v"]" \ 9 | "[file normalize "${script_dir}/rtl/hdmi/i2c_config.v"]" \ 10 | "[file normalize "${script_dir}/rtl/hdmi/i2c_master_bit_ctrl.v"]" \ 11 | "[file normalize "${script_dir}/rtl/hdmi/i2c_master_byte_ctrl.v"]" \ 12 | "[file normalize "${script_dir}/rtl/hdmi/i2c_master_defines.v"]" \ 13 | "[file normalize "${script_dir}/rtl/hdmi/i2c_master_top.v"]" \ 14 | ] 15 | 16 | # Add files for constraint 17 | set xdc_files [list \ 18 | "[file normalize "${script_dir}/constr/hdmi.xdc"]" \ 19 | ] 20 | 21 | source ${script_dir}/../common.tcl 22 | -------------------------------------------------------------------------------- /fpga/board/axu3cg/rtl/addr_mapper.v: -------------------------------------------------------------------------------- 1 | module addr_mapper ( 2 | `axi_slave_if(s_axi, 64, 8), 3 | `axi_master_if(m_axi, 64, 8) 4 | ); 5 | 6 | assign m_axi_awaddr = {4'd0, 2'b01, s_axi_awaddr[29:0]}; 7 | assign m_axi_araddr = {4'd0, 2'b01, s_axi_araddr[29:0]}; 8 | assign m_axi_arburst = s_axi_arburst; 9 | assign m_axi_arcache = s_axi_arcache; 10 | assign m_axi_arid = s_axi_arid ; 11 | // assign m_axi_aruser = s_axi_aruser ; 12 | assign m_axi_arlen = s_axi_arlen ; 13 | assign m_axi_arlock = s_axi_arlock ; 14 | assign m_axi_arprot = s_axi_arprot ; 15 | assign s_axi_arready = m_axi_arready; 16 | assign m_axi_arsize = s_axi_arsize ; 17 | assign m_axi_arvalid = s_axi_arvalid; 18 | assign m_axi_awburst = s_axi_awburst; 19 | assign m_axi_awcache = s_axi_awcache; 20 | assign m_axi_awid = s_axi_awid ; 21 | // assign m_axi_awuser = s_axi_awuser ; 22 | assign m_axi_awlen = s_axi_awlen ; 23 | assign m_axi_awlock = s_axi_awlock ; 24 | assign m_axi_awprot = s_axi_awprot ; 25 | assign s_axi_awready = m_axi_awready; 26 | assign m_axi_awsize = s_axi_awsize ; 27 | assign m_axi_awvalid = s_axi_awvalid; 28 | assign s_axi_bid = m_axi_bid ; 29 | assign m_axi_bready = s_axi_bready ; 30 | assign s_axi_bresp = m_axi_bresp ; 31 | assign s_axi_bvalid = m_axi_bvalid ; 32 | assign s_axi_rdata = m_axi_rdata ; 33 | assign s_axi_rid = m_axi_rid ; 34 | assign s_axi_rlast = m_axi_rlast ; 35 | assign m_axi_rready = s_axi_rready ; 36 | assign s_axi_rresp = m_axi_rresp ; 37 | assign s_axi_rvalid = m_axi_rvalid ; 38 | assign m_axi_wdata = s_axi_wdata ; 39 | assign m_axi_wlast = s_axi_wlast ; 40 | assign s_axi_wready = m_axi_wready ; 41 | assign m_axi_wstrb = s_axi_wstrb ; 42 | assign m_axi_wvalid = s_axi_wvalid ; 43 | assign m_axi_arqos = s_axi_arqos ; 44 | assign m_axi_awqos = s_axi_awqos ; 45 | 46 | endmodule 47 | -------------------------------------------------------------------------------- /fpga/board/axu3cg/rtl/hdmi/i2c_config.v: -------------------------------------------------------------------------------- 1 | module i2c_config( 2 | input rst, 3 | input clk, 4 | 5 | output reg error, 6 | output done, 7 | 8 | inout i2c_scl, 9 | inout i2c_sda 10 | ); 11 | wire scl_pad_i; 12 | wire scl_pad_o; 13 | wire scl_padoen_o; 14 | 15 | wire sda_pad_i; 16 | wire sda_pad_o; 17 | wire sda_padoen_o; 18 | 19 | assign sda_pad_i = i2c_sda; 20 | assign i2c_sda = ~sda_padoen_o ? sda_pad_o : 1'bz; 21 | assign scl_pad_i = i2c_scl; 22 | assign i2c_scl = ~scl_padoen_o ? scl_pad_o : 1'bz; 23 | 24 | reg i2c_read_req; 25 | wire i2c_read_req_ack; 26 | reg i2c_write_req; 27 | wire i2c_write_req_ack; 28 | wire[7:0] i2c_slave_dev_addr; 29 | wire[7:0] i2c_slave_reg_addr; 30 | wire[7:0] i2c_write_data; 31 | wire[7:0] i2c_read_data; 32 | 33 | wire err; 34 | reg[7:0] lut_index; 35 | reg[23:0] lut_data; 36 | 37 | reg[2:0] state; 38 | 39 | localparam S_IDLE = 0; 40 | localparam S_WR_I2C_CHECK = 1; 41 | localparam S_WR_I2C = 2; 42 | localparam S_WR_I2C_DONE = 3; 43 | 44 | 45 | assign done = (state == S_WR_I2C_DONE); 46 | assign {i2c_slave_dev_addr,i2c_slave_reg_addr,i2c_write_data} = lut_data; 47 | always@(*) 48 | begin 49 | case(lut_index) 50 | 8'd0: lut_data <= {8'h72,8'h08,8'h35}; 51 | 8'd1: lut_data <= {8'h7a,8'h2f,8'h00}; 52 | default:lut_data <= {8'hff,8'hff,8'hff}; 53 | endcase 54 | end 55 | 56 | always@(posedge clk or posedge rst) 57 | begin 58 | if(rst) 59 | begin 60 | state <= S_IDLE; 61 | error <= 1'b0; 62 | lut_index <= 8'd0; 63 | end 64 | else 65 | case(state) 66 | S_IDLE: 67 | begin 68 | state <= S_WR_I2C_CHECK; 69 | error <= 1'b0; 70 | lut_index <= 8'd0; 71 | end 72 | S_WR_I2C_CHECK: 73 | begin 74 | if(i2c_slave_dev_addr != 8'hff) 75 | begin 76 | i2c_write_req <= 1'b1; 77 | state <= S_WR_I2C; 78 | end 79 | else 80 | begin 81 | state <= S_WR_I2C_DONE; 82 | end 83 | end 84 | S_WR_I2C: 85 | begin 86 | if(i2c_write_req_ack) 87 | begin 88 | error <= err ? 1'b1 : error; 89 | lut_index <= lut_index + 8'd1; 90 | i2c_write_req <= 1'b0; 91 | state <= S_WR_I2C_CHECK; 92 | end 93 | end 94 | S_WR_I2C_DONE: 95 | begin 96 | state <= S_WR_I2C_DONE; 97 | end 98 | default: 99 | state <= S_IDLE; 100 | endcase 101 | end 102 | 103 | 104 | 105 | i2c_master_top i2c_master_top_m0 106 | ( 107 | .rst(rst), 108 | .clk(clk), 109 | 110 | // I2C signals 111 | // i2c clock line 112 | .scl_pad_i(scl_pad_i), // SCL-line input 113 | .scl_pad_o(scl_pad_o), // SCL-line output (always 1'b0) 114 | .scl_padoen_o(scl_padoen_o), // SCL-line output enable (active low) 115 | 116 | // i2c data line 117 | .sda_pad_i(sda_pad_i), // SDA-line input 118 | .sda_pad_o(sda_pad_o), // SDA-line output (always 1'b0) 119 | .sda_padoen_o(sda_padoen_o), // SDA-line output enable (active low) 120 | 121 | .i2c_read_req(i2c_read_req), 122 | .i2c_read_req_ack(i2c_read_req_ack), 123 | .i2c_write_req(i2c_write_req), 124 | .i2c_write_req_ack(i2c_write_req_ack), 125 | .i2c_slave_dev_addr(i2c_slave_dev_addr), 126 | .i2c_slave_reg_addr(i2c_slave_reg_addr), 127 | .i2c_write_data(i2c_write_data), 128 | .i2c_read_data(i2c_read_data), 129 | .error(err) 130 | ); 131 | endmodule -------------------------------------------------------------------------------- /fpga/board/axu3cg/rtl/hdmi/i2c_master_defines.v: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | //// //// 3 | //// WISHBONE rev.B2 compliant I2C Master controller defines //// 4 | //// //// 5 | //// //// 6 | //// Author: Richard Herveille //// 7 | //// richard@asics.ws //// 8 | //// www.asics.ws //// 9 | //// //// 10 | //// Downloaded from: http://www.opencores.org/projects/i2c/ //// 11 | //// //// 12 | ///////////////////////////////////////////////////////////////////// 13 | //// //// 14 | //// Copyright (C) 2001 Richard Herveille //// 15 | //// richard@asics.ws //// 16 | //// //// 17 | //// This source file may be used and distributed without //// 18 | //// restriction provided that this copyright statement is not //// 19 | //// removed from the file and that any derivative work contains //// 20 | //// the original copyright notice and the associated disclaimer.//// 21 | //// //// 22 | //// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY //// 23 | //// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED //// 24 | //// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //// 25 | //// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR //// 26 | //// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //// 27 | //// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES //// 28 | //// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE //// 29 | //// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR //// 30 | //// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF //// 31 | //// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT //// 32 | //// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT //// 33 | //// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //// 34 | //// POSSIBILITY OF SUCH DAMAGE. //// 35 | //// //// 36 | ///////////////////////////////////////////////////////////////////// 37 | 38 | // CVS Log 39 | // 40 | // $Id: i2c_master_defines.v,v 1.3 2001-11-05 11:59:25 rherveille Exp $ 41 | // 42 | // $Date: 2001-11-05 11:59:25 $ 43 | // $Revision: 1.3 $ 44 | // $Author: rherveille $ 45 | // $Locker: $ 46 | // $State: Exp $ 47 | // 48 | // Change History: 49 | // $Log: not supported by cvs2svn $ 50 | 51 | 52 | // I2C registers wishbone addresses 53 | 54 | // bitcontroller states 55 | `define I2C_CMD_NOP 4'b0000 56 | `define I2C_CMD_START 4'b0001 57 | `define I2C_CMD_STOP 4'b0010 58 | `define I2C_CMD_WRITE 4'b0100 59 | `define I2C_CMD_READ 4'b1000 60 | -------------------------------------------------------------------------------- /fpga/board/axu3cg/rtl/hdmi/timescale.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 10ps 2 | 3 | -------------------------------------------------------------------------------- /fpga/board/axu3cg/rtl/system_top.v: -------------------------------------------------------------------------------- 1 | `include "axi.vh" 2 | 3 | `define HAS_HDMI 4 | 5 | module system_top ( 6 | `ifdef HAS_HDMI 7 | inout hdmi_scl, 8 | inout hdmi_sda, 9 | output hdmi_nreset, 10 | output hdmi_clk, 11 | output hdmi_hsync, 12 | output hdmi_vsync, 13 | output hdmi_videovalid, 14 | output [23:0] hdmi_rgb 15 | `endif 16 | //output [7:0] led 17 | ); 18 | 19 | `axi_wire(AXI_MEM_MAPPED, 64, 8); 20 | `axi_wire(AXI_MEM, 64, 8); 21 | `axi_wire(AXI_MMIO, 64, 8); 22 | `axi_wire(AXI_DMA, 64, 16); 23 | 24 | wire coreclk; 25 | wire corerstn; 26 | wire clk40; 27 | wire clk27; 28 | wire uncoreclk; 29 | wire uncorerstn; 30 | 31 | wire [4:0] intrs; 32 | 33 | zynq_soc zynq_soc_i ( 34 | `axi_connect_if(AXI_MEM, AXI_MEM_MAPPED), 35 | `axi_connect_if(AXI_MMIO, AXI_MMIO), 36 | `axi_connect_if(AXI_DMA, AXI_DMA), 37 | 38 | .intrs(intrs), 39 | 40 | `ifdef HAS_HDMI 41 | .vga_rgb(hdmi_rgb), 42 | .vga_hsync(hdmi_hsync), 43 | .vga_vsync(hdmi_vsync), 44 | .vga_valid(hdmi_videovalid), 45 | .clk27(clk27), 46 | .clk40(clk40), 47 | `endif 48 | 49 | .coreclk(coreclk), 50 | .corerstn(corerstn), 51 | .uncoreclk(uncoreclk), 52 | .uncorerstn(uncorerstn) 53 | ); 54 | 55 | addr_mapper addr_mapper_i( 56 | `axi_connect_if(s_axi, AXI_MEM), 57 | `axi_connect_if(m_axi, AXI_MEM_MAPPED) 58 | ); 59 | 60 | reg corerstn_ff; 61 | always@(posedge uncoreclk) begin 62 | corerstn_ff <= corerstn; 63 | end 64 | 65 | reg corerstn_sync[1:0]; 66 | always@(posedge coreclk) begin 67 | corerstn_sync[0] <= corerstn_ff; 68 | corerstn_sync[1] <= corerstn_sync[0]; 69 | end 70 | 71 | nutshell nutshell_i( 72 | `axi_connect_if(AXI_MEM, AXI_MEM), 73 | `axi_connect_if(AXI_DMA, AXI_DMA), 74 | `axi_connect_if_no_id(AXI_MMIO, AXI_MMIO), 75 | 76 | .intrs(intrs), 77 | 78 | .coreclk(coreclk), 79 | .corerstn(corerstn_sync[1]), 80 | .uncoreclk(uncoreclk), 81 | .uncorerstn(uncorerstn) 82 | ); 83 | 84 | `ifdef HAS_HDMI 85 | i2c_config hdmi_i2c_config( 86 | .rst(!uncorerstn), 87 | .clk(clk27), 88 | .i2c_scl(hdmi_scl), 89 | .i2c_sda(hdmi_sda) 90 | ); 91 | 92 | assign hdmi_nreset = uncorerstn; 93 | assign hdmi_clk = clk40; 94 | `endif 95 | 96 | endmodule 97 | -------------------------------------------------------------------------------- /fpga/board/common.tcl: -------------------------------------------------------------------------------- 1 | if {[llength $argv] > 0} { 2 | set project_name [lindex $argv 0] 3 | set s [split $project_name -] 4 | set prj [lindex $s 0] 5 | set brd [lindex $s 1] 6 | } else { 7 | puts "project full name is not given!" 8 | return 1 9 | } 10 | 11 | if {[llength $argv] > 1} { 12 | set standalone [lindex $argv 1] 13 | } else { 14 | puts "standalone mode is not given!" 15 | return 1 16 | } 17 | 18 | proc add_bd {tcl_file} { 19 | source ${tcl_file} 20 | save_bd_design 21 | close_bd_design $design_name 22 | set_property synth_checkpoint_mode Hierarchical [get_files *${design_name}.bd] 23 | } 24 | 25 | set fpga_dir ${script_dir}/../.. 26 | set project_dir ${script_dir}/build/$project_name 27 | set rtl_dir ${script_dir}/rtl 28 | set lib_dir ${fpga_dir}/lib 29 | set bd_dir ${script_dir}/bd 30 | set constr_dir ${script_dir}/constr 31 | set data_dir ${script_dir}/data 32 | set ip_dir ${script_dir}/ip 33 | set nutshell_build_dir ${fpga_dir}/../build/rtl 34 | 35 | create_project $project_name -force -dir $project_dir/ -part ${device} 36 | if {[info exists board]} { 37 | set_property board_part $board [current_project] 38 | } 39 | 40 | # lib files 41 | set inc_files [list \ 42 | "[file normalize "${lib_dir}/include/axi.vh"]" \ 43 | ] 44 | add_files -norecurse -fileset sources_1 $inc_files 45 | set_property is_global_include true [get_files $inc_files] 46 | 47 | # Add files for nutshell 48 | set nutshell_rtl [glob -d ${nutshell_build_dir} *.sv or *.v] 49 | 50 | foreach src_file ${nutshell_rtl} { 51 | lappend src_files [file normalize $src_file] 52 | } 53 | 54 | add_files -norecurse -fileset sources_1 $src_files 55 | set_property file_type Verilog -objects [get_files -of_objects [get_filesets sources_1] *NutShell.sv] 56 | # vivado do not support a system verilog file be the top of a reference design, this may be removed as reference design is not need actually 57 | 58 | if {[info exists xdc_files]} { 59 | add_files -norecurse -fileset constrs_1 $xdc_files 60 | } 61 | 62 | # Block Designs 63 | if {${standalone} == "true"} { 64 | add_bd ${bd_dir}/standalone.tcl 65 | make_wrapper -files [get_files *system_top.bd] -top 66 | add_files -norecurse -fileset sources_1 $project_dir/$project_name.srcs/sources_1/bd/system_top/hdl/system_top_wrapper.v 67 | set topmodule system_top_wrapper 68 | } else { 69 | add_bd ${fpga_dir}/NutShell.tcl 70 | add_bd ${bd_dir}/arm.tcl 71 | set topmodule system_top 72 | } 73 | 74 | # setting top module for FPGA flow and simulation flow 75 | set_property "top" $topmodule [current_fileset] 76 | 77 | # setting Synthesis options 78 | set_property strategy {Vivado Synthesis defaults} [get_runs synth_1] 79 | # keep module port names in the netlist 80 | set_property STEPS.SYNTH_DESIGN.ARGS.FLATTEN_HIERARCHY {none} [get_runs synth_1] 81 | 82 | # setting Implementation options 83 | set_property steps.phys_opt_design.is_enabled true [get_runs impl_1] 84 | 85 | # update compile order 86 | update_compile_order -fileset sources_1 87 | -------------------------------------------------------------------------------- /fpga/board/pynq/mk.tcl: -------------------------------------------------------------------------------- 1 | set device xc7z020-1-clg400 2 | set board tul.com.tw:pynq-z2:part0:1.0 3 | 4 | set script_dir [file dirname [info script]] 5 | 6 | # Add files for system top 7 | set src_files [list \ 8 | ] 9 | 10 | # Add files for constraint 11 | #set xdc_files [list \ 12 | # "[file normalize "${script_dir}/constr/constr.xdc"]" \ 13 | # "[file normalize "${script_dir}/constr/vga.xdc"]" \ 14 | #] 15 | 16 | source ${script_dir}/../common.tcl 17 | -------------------------------------------------------------------------------- /fpga/boot/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | -------------------------------------------------------------------------------- /fpga/boot/axu3cg/u-boot.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OSCPU/NutShell/fc12171d929e7e589fab9f794ab63ce12e6c594e/fpga/boot/axu3cg/u-boot.elf -------------------------------------------------------------------------------- /fpga/boot/bootgen-zynq-standalone.bif: -------------------------------------------------------------------------------- 1 | the_ROM_image: 2 | { 3 | [bootloader] build/zynq/fsbl.elf 4 | build/zynq/fpga.bit 5 | ../resource/fsbl-loader/fsbl-loader.elf 6 | } 7 | -------------------------------------------------------------------------------- /fpga/boot/bootgen-zynq.bif: -------------------------------------------------------------------------------- 1 | the_ROM_image: 2 | { 3 | [bootloader] build/zynq/fsbl.elf 4 | // build/zynq/system_top.bit 5 | build/zynq/u-boot.elf 6 | } 7 | -------------------------------------------------------------------------------- /fpga/boot/bootgen-zynqmp.bif: -------------------------------------------------------------------------------- 1 | the_ROM_image: 2 | { 3 | [fsbl_config] a53_x64 4 | [bootloader] build/zynqmp/fsbl.elf 5 | [pmufw_image] build/zynqmp/pmufw.elf 6 | // [destination_device=pl] build/zynqmp/system_top.bit 7 | [destination_cpu=a53-0, exception_level=el-3,trustzone] build/zynqmp/bl31.elf 8 | [destination_cpu=a53-0, exception_level=el-2] build/zynqmp/u-boot.elf 9 | } 10 | -------------------------------------------------------------------------------- /fpga/boot/bug-list.md: -------------------------------------------------------------------------------- 1 | 2 | ## sidewinder 3 | 4 | To make the SD card work, do the followings 5 | * use a class10 SD card 6 | * `fsbl/psu_init.c`: search for `IOU_SLCR_BANK1_CTRL5_OFFSET`, change `0x2000FFFU` to `0x3FFFFFFU` (already done inside `mk.tcl`) 7 | * add "disable-wp;" property to the node of "sdhci@ff170000" in device tree 8 | 9 | * remove gem3.phy node 10 | 11 | ## ultraZ 12 | 13 | To make the SD card work, do the followings 14 | * should use 2016.4 dts 15 | * add "no-1-8-v;" property to the node of "sdhci@ff170000" in device tree 16 | * modify gem3.phyc.reg to <0x5> 17 | 18 | ## axu3cg 19 | 20 | * should use u-boot.elf from petalinux 21 | * it seems that the default zcu102 config in u-boot can not adapt to this board 22 | * add "no-1-8-v;" property to the node of "sdhci@ff170000" in device tree 23 | * modify gem3.phyc.reg to <0x1> 24 | * remove `pinctrl-names` and `pinctrl-0` property from node `uart1` 25 | * this will fix the issue of unable to input in linux 26 | 27 | ## u-boot 28 | 29 | define marco `CONFIG_ENV_OVERWRITE` in `u-boot-xlnx/include/configs/xilinx-zynqmp.h` to make `ethaddr` environment variable writable 30 | -------------------------------------------------------------------------------- /fpga/boot/mk.tcl: -------------------------------------------------------------------------------- 1 | # usage: hsi -nojournal -nolog -source [this tcl file] -tclargs [hdf file] [prj-brd] 2 | 3 | if {[llength $argv] > 0} { 4 | set project_name [lindex $argv 0] 5 | } else { 6 | puts "hdf file path is not given!" 7 | return 1 8 | } 9 | 10 | if {[llength $argv] > 1} { 11 | set standalone [lindex $argv 1] 12 | } else { 13 | puts "standalone mode is not given!" 14 | return 1 15 | } 16 | 17 | set s [split $project_name -] 18 | set prj [lindex $s 0] 19 | set brd [lindex $s 1] 20 | 21 | set script_dir [file normalize [file dirname [info script]]] 22 | set build_dir ${script_dir}/build/${project_name} 23 | 24 | set device_tree_repo_path "/home/yzh/xilinx/device-tree-xlnx" 25 | 26 | switch -regexp -- $brd { 27 | zedboard|pynq { 28 | set processor ps7_cortexa9_0 29 | set brd_version zedboard 30 | set arch zynq 31 | } 32 | zcu102|sidewinder|ultraZ|axu3cg|PXIe { 33 | set processor psu_cortexa53_0 34 | set brd_version zcu102-rev1.0 35 | set arch zynqmp 36 | } 37 | default { 38 | puts "Unsupported board $brd" 39 | return 1 40 | } 41 | } 42 | 43 | exec mkdir -p ${script_dir}/build/${arch} 44 | set hdf_file ${script_dir}/build/${arch}/ps.hdf 45 | set hw_design [open_hw_design ${hdf_file}] 46 | 47 | generate_app -hw $hw_design -os standalone -proc $processor -app ${arch}_fsbl -sw fsbl -dir ${build_dir}/fsbl 48 | if {$brd == "sidewinder"} { 49 | # see bug-list.md 50 | exec sed -i -e "s/0x03FFFFFFU, 0x02000FFFU);/0x03FFFFFFU, 0x03FFFFFFU);/g" ${build_dir}/fsbl/psu_init.c 51 | } 52 | if { [catch { exec make -C ${build_dir}/fsbl } msg ] } { } 53 | 54 | if {$arch == "zynqmp"} { 55 | generate_app -hw $hw_design -os standalone -proc psu_pmu_0 -app zynqmp_pmufw -compile -sw pmufw -dir ${build_dir}/pmufw 56 | exec ln -sf ${build_dir}/pmufw/executable.elf ${script_dir}/build/${arch}/pmufw.elf 57 | } 58 | 59 | exec mkdir -p ${script_dir}/build/${arch} 60 | exec ln -sf ${build_dir}/fsbl/executable.elf ${script_dir}/build/${arch}/fsbl.elf 61 | 62 | if {$standalone == "true"} { 63 | set bif_file ${script_dir}/bootgen-${arch}-standalone.bif 64 | if { [catch { exec make -C ${script_dir}/../resource/fsbl-loader } msg ] } { } 65 | } else { 66 | set bif_file ${script_dir}/bootgen-${arch}.bif 67 | } 68 | exec bootgen -arch ${arch} -image $bif_file -w -o i ${build_dir}/BOOT.BIN 69 | 70 | #device tree 71 | set_repo_path ${device_tree_repo_path} 72 | create_sw_design device-tree -os device_tree -proc $processor 73 | if {$brd != "ultraZ"} { 74 | set_property CONFIG.periph_type_overrides "{BOARD ${brd_version}}" [get_os] 75 | } 76 | generate_target -dir ${build_dir}/dts 77 | 78 | exit 79 | -------------------------------------------------------------------------------- /fpga/boot/pynq/BOOT.BIN: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OSCPU/NutShell/fc12171d929e7e589fab9f794ab63ce12e6c594e/fpga/boot/pynq/BOOT.BIN -------------------------------------------------------------------------------- /fpga/boot/pynq/RV_BOOT.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OSCPU/NutShell/fc12171d929e7e589fab9f794ab63ce12e6c594e/fpga/boot/pynq/RV_BOOT.bin -------------------------------------------------------------------------------- /fpga/boot/standalone.md: -------------------------------------------------------------------------------- 1 | # Stand-Alone Mode 2 | 3 | In stand-alone mode, control is directly transferred to PL (Program Logic) through FSBL (First Stage BootLoader) after the board is powered on, so that PL has access to on-board peripherals such as SD card, Ethernet, etc., which is necessary to boot Debian and other OS. 4 | 5 | We use PYNQ-Z2 board as example to demonstrate how to prepare SD card in stand-alone mode. 6 | 7 | ## Build BOOT.BIN 8 | 9 | BOOT.bin is the default filename of packaged hardware-related binary files. [Here](pynq/BOOT.BIN) is a pre-built and currently-used BOOT.BIN. 10 | 11 | You can also build it yourself. Please refer to the following process. 12 | 13 | * create a project in Vivado and generate bitstream 14 | 15 | ``` 16 | cd $(NUTSHELL_HOME)/fpga 17 | make PRJ=myprj BOARD=pynq STANDALONE=true vivado 18 | ``` 19 | 20 | * generate hardware description file in Vivado 21 | 22 | ``` 23 | Vivado -> File -> Export -> Export Hardware 24 | ``` 25 | 26 | * do bootgen initially 27 | 28 | ``` 29 | cd $(NUTSHELL_HOME)/fpga 30 | make bootgen PRJ=myprj BOARD=pynq STANDALONE=true 31 | # this will report some error messages 32 | ``` 33 | 34 | * create project-related links 35 | 36 | ``` 37 | cd $(NUTSHELL_HOME)/fpga/boot/build/zynq 38 | ln -sf $(NUTSHELL_HOME)/fpga/board/pynq/build/myprj-pynq/myprj-pynq.sdk/system_top_wrapper.hdf ps.hdf 39 | ln -sf $(NUTSHELL_HOME)/fpga/board/pynq/build/myprj-pynq/myprj-pynq.runs/impl_1/system_top_wrapper.bit fpga.bit 40 | # modify FSBL_LOC in $(NUTSHELL_HOME)/fpga/resource/fsbl-loader/Makefile like this: 41 | # FSBL_LOC = ../../boot/build/myprj-pynq/fsbl 42 | ``` 43 | 44 | * generate BOOT.BIN 45 | 46 | ``` 47 | cd $(NUTSHELL_HOME)/fpga 48 | make bootgen PRJ=myprj BOARD=pynq STANDALONE=true 49 | ``` 50 | 51 | 52 | 53 | ## Build RV_BOOT.bin 54 | 55 | RV_BOOT.bin is the default filename of linux-kernel image. [Here](pynq/RV_BOOT.bin) is a pre-built and currently-used image. You can also build it yourself by riscv-pk and riscv-linux (currently not avaliable to the public). 56 | 57 | 58 | 59 | ## Build rootfs in SD Card 60 | 61 | * New an `ext4` partition `mmcblk0p2` in SD card. Refer to the step of [here](https://wiki.debian.org/InstallingDebianOn/Xilinx/ZC702/wheezy#SD_Card_root) before executing `debootstrap`. 62 | 63 | * Download the debian base system to `mmcblk0p2` with `qemu-debootstrap`. 64 | 65 | ``` 66 | sudo qemu-debootstrap --arch riscv64 unstable /mnt http://deb.debian.org/debian-ports 67 | sudo chroot /mnt /bin/bash 68 | passwd 69 | apt-get update 70 | apt-get install net-tools openssh-server vim build-essential minicom tmux libreadline-dev 71 | exit 72 | ``` 73 | 74 | * Add a line of `ttyPS0` in `/mnt/etc/securetty` to allow login debian via `ttyPS0`. See [here](http://www.linuxquestions.org/questions/linux-newbie-8/login-incorrect-error-after-boot-no-password-prompted-881131/) for more details. 75 | 76 | * Add a line of `PermitRootLogin yes` in `/mnt/etc/ssh/sshd_config` to enable root login via ssh. See [here](https://linuxconfig.org/enable-ssh-root-login-on-debian-linux-server) for more details. 77 | * Add the following lines to `/mnt/etc/fstab` 78 | 79 | ``` 80 | # 81 | proc /proc proc defaults 0 0 82 | /dev/mmcblk0p1 /boot vfat defaults 0 2 83 | /dev/mmcblk0p2 / ext4 errors=remount-ro 0 1 84 | ``` 85 | 86 | Put `BOOT.BIN`, `RV_BOOT.BIN` generated in the previous steps into `/dev/mmcblk0p1`. 87 | Finally, insert the SD card into the board. Pull down SW0 on pynq board to boot Debian. -------------------------------------------------------------------------------- /fpga/resource/ddr-loader/ddr-loader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | enum { BOARD_ultraZ, BOARD_zedboard, BOARD_zcu102, BOARD_sidewinder }; 18 | static const struct BoardConfig { 19 | char *name; 20 | uintptr_t ddr_size; 21 | uintptr_t ddr_base; 22 | uintptr_t gpio_reset_base; 23 | } board_config [] = { 24 | [BOARD_ultraZ] = {"ultraZ", 0x40000000, 0x40000000, 0x80001000}, 25 | [BOARD_axu3cg] = {"axu3cg", 0x40000000, 0x40000000, 0x80001000}, 26 | [BOARD_zedboard] = {"zedboard", 0x10000000, 0x10000000, 0x41200000}, 27 | [BOARD_zcu102] = {"zcu102", 0x80000000, 0x800000000, 0x80010000}, 28 | [BOARD_sidewinder] = {"sidewinder", 0x80000000, 0x800000000, 0x80010000} 29 | }; 30 | 31 | #define NR_BOARD (sizeof(board_config) / sizeof(board_config[0])) 32 | 33 | const struct BoardConfig *bc; 34 | 35 | #define GPIO_RESET_TOTAL_SIZE 0x1000 36 | 37 | void *ddr_base; 38 | volatile uint32_t *gpio_reset_base; 39 | int fd; 40 | 41 | static inline void my_fread(char *filename, uint64_t *addr) { 42 | FILE *fp = fopen(filename, "rb"); 43 | assert(fp); 44 | 45 | fseek(fp, 0, SEEK_END); 46 | long size = ftell(fp); 47 | printf("sizeof(%s) = %ld\n", filename, size); 48 | 49 | fseek(fp, 0, SEEK_SET); 50 | fread(addr, size, 1, fp); 51 | 52 | fclose(fp); 53 | } 54 | 55 | void loader(char *imgfile, uintptr_t offset) { 56 | my_fread(imgfile, ddr_base + offset); 57 | // my_fread(dtbfile, ddr_base + offset + 0x8); 58 | // strcpy(ddr_base, "t"); 59 | strcpy(ddr_base + 0x1000, "ref"); 60 | } 61 | 62 | void* create_map(size_t size, int fd, off_t offset) { 63 | void *base = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset); 64 | 65 | if (base == MAP_FAILED) { 66 | perror("init_mem mmap failed:"); 67 | close(fd); 68 | exit(1); 69 | } 70 | 71 | printf("mapping paddr 0x%lx to vaddr 0x%" PRIxPTR "\n", offset, (uintptr_t)base); 72 | 73 | return base; 74 | } 75 | 76 | void init_map() { 77 | fd = open("/dev/mem", O_RDWR|O_SYNC); 78 | if (fd == -1) { 79 | perror("init_map open failed:"); 80 | exit(1); 81 | } 82 | 83 | printf("board = %s, ddr_size = 0x%" PRIxPTR ", ddr_base = 0x%" PRIxPTR "\n", 84 | bc->name, bc->ddr_size, bc->ddr_base); 85 | ddr_base = create_map(bc->ddr_size, fd, bc->ddr_base); 86 | gpio_reset_base = create_map(GPIO_RESET_TOTAL_SIZE, fd, bc->gpio_reset_base); 87 | } 88 | 89 | void finish_map() { 90 | munmap((void *)gpio_reset_base, GPIO_RESET_TOTAL_SIZE); 91 | munmap((void *)ddr_base, bc->ddr_size); 92 | close(fd); 93 | } 94 | 95 | void help() { 96 | printf("Usage: axi-loader [board] reset\n"); 97 | printf(" axi-loader [board] fetch [ddr_offset]\n"); 98 | printf(" axi-loader [board] [bin] [ddr_offset]\n"); 99 | printf("Supported boards:\n"); 100 | int i; 101 | for (i = 0; i < NR_BOARD; i ++) { 102 | printf("%s ", board_config[i].name); 103 | } 104 | } 105 | 106 | void resetn(int val) { 107 | gpio_reset_base[0] = val; 108 | } 109 | 110 | int main(int argc, char *argv[]) { 111 | if (argc > 1 && strcmp(argv[1], "-h") == 0) { 112 | help(); 113 | return 0; 114 | } 115 | 116 | uintptr_t offset = 0; 117 | if (argc > 3) { 118 | char *p; 119 | offset = strtoll(argv[3], &p, 0); 120 | if (!(argv[3][0] != '\0' && *p == '\0')) { 121 | printf("invalid offset = %s, set offset = 0\n", argv[3]); 122 | offset = 0; 123 | } 124 | } 125 | 126 | int j; 127 | for (j = 0; j < NR_BOARD; j ++) { 128 | if (strcmp(argv[1], board_config[j].name) == 0) { 129 | bc = &board_config[j]; 130 | break; 131 | } 132 | } 133 | if (j == NR_BOARD) { 134 | printf("invalid board = %s\n", argv[1]); 135 | help(); 136 | exit(1); 137 | } 138 | 139 | init_map(); 140 | 141 | if (strcmp(argv[2], "reset") == 0) { 142 | resetn(0); 143 | finish_map(); 144 | return 0; 145 | } 146 | else if (strcmp(argv[2], "fetch") == 0) { 147 | printf("fetch word at offset = 0x%lx, result = 0x%08x\n", 148 | offset, *(uint32_t *)(ddr_base + offset)); 149 | finish_map(); 150 | return 0; 151 | } 152 | 153 | printf("loading %s to offset = 0x%" PRIxPTR "\n", argv[2], offset); 154 | resetn(0); 155 | usleep(1000); 156 | loader(argv[2], offset); 157 | resetn(1); 158 | 159 | finish_map(); 160 | 161 | return 0; 162 | } 163 | -------------------------------------------------------------------------------- /fpga/resource/fsbl-loader/.gitignore: -------------------------------------------------------------------------------- 1 | *.d 2 | -------------------------------------------------------------------------------- /fpga/resource/fsbl-loader/Makefile: -------------------------------------------------------------------------------- 1 | RM := rm -rf 2 | 3 | ifneq ($(MAKECMDGOALS),clean) 4 | ifneq ($(strip $(S_UPPER_DEPS)),) 5 | -include $(S_UPPER_DEPS) 6 | endif 7 | ifneq ($(strip $(C_DEPS)),) 8 | -include $(C_DEPS) 9 | endif 10 | endif 11 | 12 | APP = fsbl-loader 13 | OBJS += $(APP).o 14 | LIBS := -Wl,--start-group,-lxilffs,-lxil,-lgcc,-lc,--end-group 15 | LDSCRIPT = lscript.ld 16 | FSBL_LOC = ../../boot/build/argo-pynq/fsbl 17 | BSP_PATH = $(FSBL_LOC)/zynq_fsbl_bsp/ps7_cortexa9_0 18 | INCLUDEPATH := -I$(BSP_PATH)/include -I. 19 | LIBPATH := -L$(BSP_PATH)/lib 20 | 21 | CC = arm-none-eabi-gcc 22 | CFLAGS = -MMD -MP -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -Wall -O2 $(INCLUDEPATH) 23 | LN_FLAGS = -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -Wl,-build-id=none -specs=$(FSBL_LOC)/Xilinx.spec -lrsa -Wl,--start-group,-lxil,-lgcc,-lc,--end-group -Wl,--start-group,-lxilffs,-lxil,-lgcc,-lc,--end-group -Wl,--start-group,-lrsa,-lxil,-lgcc,-lc,--end-group -Wl,--gc-sections 24 | 25 | 26 | all: $(APP).elf 27 | 28 | $(APP).elf: $(OBJS) $(LDSCRIPT) $(USER_OBJS) 29 | $(CC) $(LN_FLAGS) -Wl,-T -Wl,$(LDSCRIPT) $(LIBPATH) -o $@ $(OBJS) $(USER_OBJS) $(LIBS) 30 | 31 | # Other Targets 32 | clean: 33 | -$(RM) $(APP).elf *.d *.o 34 | -@echo ' ' 35 | 36 | %.o: %.c 37 | $(CC) $(CFLAGS) -c -o "$@" "$<" 38 | 39 | .PHONY: all clean dependents 40 | -------------------------------------------------------------------------------- /ready-to-run/linux.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OSCPU/NutShell/fc12171d929e7e589fab9f794ab63ce12e6c594e/ready-to-run/linux.bin -------------------------------------------------------------------------------- /ready-to-run/microbench.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OSCPU/NutShell/fc12171d929e7e589fab9f794ab63ce12e6c594e/ready-to-run/microbench.bin -------------------------------------------------------------------------------- /ready-to-run/riscv64-nemu-interpreter-so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OSCPU/NutShell/fc12171d929e7e589fab9f794ab63ce12e6c594e/ready-to-run/riscv64-nemu-interpreter-so -------------------------------------------------------------------------------- /scalastyle-config.xml: -------------------------------------------------------------------------------- 1 | 2 | Scalastyle standard configuration 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | No lines ending with a ; 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | |\|\||&&|:=|<>|<=|>=|!=|===|<<|>>|##|unary_(~|\-%?|!))$]]> 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /scripts/statistics.py: -------------------------------------------------------------------------------- 1 | mymap = {} 2 | last = "" 3 | 4 | with open("../build/SimTop.v", "r") as f: 5 | line = f.readline() 6 | cnt = 0 7 | while(line): 8 | if "module " in line: 9 | if last!="" : 10 | mymap[last] = cnt 11 | last = line[6:-2] 12 | cnt = 1 13 | else: 14 | cnt = cnt + 1 15 | line = f.readline() 16 | for k,v in mymap.items(): 17 | print(k, v) -------------------------------------------------------------------------------- /src/main/scala/bus/axi4/AXI4.scala: -------------------------------------------------------------------------------- 1 | // See LICENSE.SiFive for license details. 2 | 3 | package bus.axi4 4 | 5 | import chisel3._ 6 | import chisel3.util._ 7 | 8 | import nutcore.HasNutCoreParameter 9 | import utils._ 10 | 11 | object AXI4Parameters extends HasNutCoreParameter { 12 | // These are all fixed by the AXI4 standard: 13 | val lenBits = 8 14 | val sizeBits = 3 15 | val burstBits = 2 16 | val cacheBits = 4 17 | val protBits = 3 18 | val qosBits = 4 19 | val respBits = 2 20 | 21 | // These are not fixed: 22 | val idBits = 1 23 | val addrBits = PAddrBits 24 | val dataBits = DataBits 25 | val userBits = 1 26 | 27 | def CACHE_RALLOCATE = 8.U(cacheBits.W) 28 | def CACHE_WALLOCATE = 4.U(cacheBits.W) 29 | def CACHE_MODIFIABLE = 2.U(cacheBits.W) 30 | def CACHE_BUFFERABLE = 1.U(cacheBits.W) 31 | 32 | def PROT_PRIVILEGED = 1.U(protBits.W) 33 | def PROT_INSECURE = 2.U(protBits.W) 34 | def PROT_INSTRUCTION = 4.U(protBits.W) 35 | 36 | def BURST_FIXED = 0.U(burstBits.W) 37 | def BURST_INCR = 1.U(burstBits.W) 38 | def BURST_WRAP = 2.U(burstBits.W) 39 | 40 | def RESP_OKAY = 0.U(respBits.W) 41 | def RESP_EXOKAY = 1.U(respBits.W) 42 | def RESP_SLVERR = 2.U(respBits.W) 43 | def RESP_DECERR = 3.U(respBits.W) 44 | } 45 | 46 | trait AXI4HasUser { 47 | val user = Output(UInt(AXI4Parameters.userBits.W)) 48 | } 49 | 50 | trait AXI4HasData { 51 | def dataBits = AXI4Parameters.dataBits 52 | val data = Output(UInt(dataBits.W)) 53 | } 54 | 55 | trait AXI4HasId { 56 | def idBits = AXI4Parameters.idBits 57 | val id = Output(UInt(idBits.W)) 58 | } 59 | 60 | trait AXI4HasLast { 61 | val last = Output(Bool()) 62 | } 63 | 64 | // AXI4-lite 65 | 66 | class AXI4LiteBundleA extends Bundle { 67 | val addr = Output(UInt(AXI4Parameters.addrBits.W)) 68 | val prot = Output(UInt(AXI4Parameters.protBits.W)) 69 | } 70 | 71 | class AXI4LiteBundleW(override val dataBits: Int = AXI4Parameters.dataBits) extends Bundle with AXI4HasData { 72 | val strb = Output(UInt((dataBits/8).W)) 73 | } 74 | 75 | class AXI4LiteBundleB extends Bundle { 76 | val resp = Output(UInt(AXI4Parameters.respBits.W)) 77 | } 78 | 79 | class AXI4LiteBundleR(override val dataBits: Int = AXI4Parameters.dataBits) extends AXI4LiteBundleB with AXI4HasData 80 | 81 | 82 | class AXI4Lite extends Bundle { 83 | val aw = Decoupled(new AXI4LiteBundleA) 84 | val w = Decoupled(new AXI4LiteBundleW) 85 | val b = Flipped(Decoupled(new AXI4LiteBundleB)) 86 | val ar = Decoupled(new AXI4LiteBundleA) 87 | val r = Flipped(Decoupled(new AXI4LiteBundleR)) 88 | } 89 | 90 | 91 | // AXI4-full 92 | 93 | class AXI4BundleA(override val idBits: Int) extends AXI4LiteBundleA with AXI4HasId with AXI4HasUser { 94 | val len = Output(UInt(AXI4Parameters.lenBits.W)) // number of beats - 1 95 | val size = Output(UInt(AXI4Parameters.sizeBits.W)) // bytes in beat = 2^size 96 | val burst = Output(UInt(AXI4Parameters.burstBits.W)) 97 | val lock = Output(Bool()) 98 | val cache = Output(UInt(AXI4Parameters.cacheBits.W)) 99 | val qos = Output(UInt(AXI4Parameters.qosBits.W)) // 0=no QoS, bigger = higher priority 100 | // val region = UInt(width = 4) // optional 101 | 102 | override def toPrintable: Printable = p"addr = 0x${Hexadecimal(addr)}, id = ${id}, len = ${len}, size = ${size}" 103 | } 104 | 105 | // id ... removed in AXI4 106 | class AXI4BundleW(override val dataBits: Int) extends AXI4LiteBundleW(dataBits) with AXI4HasLast { 107 | override def toPrintable: Printable = p"data = ${Hexadecimal(data)}, wmask = 0x${strb}, last = ${last}" 108 | } 109 | class AXI4BundleB(override val idBits: Int) extends AXI4LiteBundleB with AXI4HasId with AXI4HasUser { 110 | override def toPrintable: Printable = p"resp = ${resp}, id = ${id}" 111 | } 112 | class AXI4BundleR(override val dataBits: Int, override val idBits: Int) extends AXI4LiteBundleR(dataBits) with AXI4HasLast with AXI4HasId with AXI4HasUser { 113 | override def toPrintable: Printable = p"resp = ${resp}, id = ${id}, data = ${Hexadecimal(data)}, last = ${last}" 114 | } 115 | 116 | 117 | class AXI4(val dataBits: Int = AXI4Parameters.dataBits, val idBits: Int = AXI4Parameters.idBits) extends AXI4Lite { 118 | override val aw = Decoupled(new AXI4BundleA(idBits)) 119 | override val w = Decoupled(new AXI4BundleW(dataBits)) 120 | override val b = Flipped(Decoupled(new AXI4BundleB(idBits))) 121 | override val ar = Decoupled(new AXI4BundleA(idBits)) 122 | override val r = Flipped(Decoupled(new AXI4BundleR(dataBits, idBits))) 123 | 124 | def dump(name: String) = { 125 | when (aw.fire) { printf(p"${GTimer()},[${name}.aw] ${aw.bits}\n") } 126 | when (w.fire) { printf(p"${GTimer()},[${name}.w] ${w.bits}\n") } 127 | when (b.fire) { printf(p"${GTimer()},[${name}.b] ${b.bits}\n") } 128 | when (ar.fire) { printf(p"${GTimer()},[${name}.ar] ${ar.bits}\n") } 129 | when (r.fire) { printf(p"${GTimer()},[${name}.r] ${r.bits}\n") } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/main/scala/bus/axi4/Delayer.scala: -------------------------------------------------------------------------------- 1 | // See LICENSE.SiFive for license details. 2 | 3 | package bus.axi4 4 | 5 | import chisel3._ 6 | import chisel3.util._ 7 | import utils._ 8 | 9 | class AXI4Delayer[T <: AXI4Lite](latency: Int = 0, _type: T = new AXI4) extends Module { 10 | val io = IO(new Bundle{ 11 | val in = Flipped(_type) 12 | val out = Flipped(Flipped(_type)) 13 | }) 14 | 15 | io.out.ar <> LatencyPipe(io.in.ar, latency) 16 | io.out.aw <> LatencyPipe(io.in.aw, latency) 17 | io.out.w <> io.in.w 18 | io.in.b <> io.out.b 19 | io.in.r <> io.out.r 20 | } 21 | -------------------------------------------------------------------------------- /src/main/scala/bus/memport/MemPort.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package bus.memport 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | import nutcore.HasNutCoreParameter 23 | 24 | trait MemoryOpConstants 25 | { 26 | val MT_X = 0.asUInt(3.W) 27 | val MT_B = 1.asUInt(3.W) 28 | val MT_H = 2.asUInt(3.W) 29 | val MT_W = 3.asUInt(3.W) 30 | val MT_D = 4.asUInt(3.W) 31 | val MT_BU = 5.asUInt(3.W) 32 | val MT_HU = 6.asUInt(3.W) 33 | val MT_WU = 7.asUInt(3.W) 34 | 35 | val M_X = "b0".asUInt(1.W) 36 | val M_XRD = "b0".asUInt(1.W) // int load 37 | val M_XWR = "b1".asUInt(1.W) // int store 38 | 39 | val DPORT = 0 40 | val IPORT = 1 41 | } 42 | 43 | object MemPortConsts extends MemoryOpConstants{} 44 | 45 | class MemPortIo(val data_width: Int) extends Bundle 46 | { 47 | val req = new DecoupledIO(new MemReq(data_width)) 48 | val resp = Flipped(new DecoupledIO(new MemResp(data_width))) 49 | } 50 | 51 | class MemReq(val data_width: Int) extends Bundle 52 | { 53 | val addr = Output(UInt(32.W)) //p(sodor_xprlen) 54 | val data = Output(UInt(data_width.W)) 55 | val fcn = Output(UInt(MemPortConsts.M_X.getWidth.W)) // memory function code 56 | val typ = Output(UInt(MemPortConsts.MT_X.getWidth.W)) // memory type 57 | } 58 | 59 | class MemResp(val data_width: Int) extends Bundle 60 | { 61 | val data = Output(UInt(data_width.W)) 62 | } -------------------------------------------------------------------------------- /src/main/scala/bus/simplebus/AddressMapper.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package bus.simplebus 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | import utils._ 23 | import nutcore.HasNutCoreParameter 24 | 25 | class SimpleBusAddressMapper(map: (Int, Long)) extends Module with HasNutCoreParameter { 26 | val io = IO(new Bundle { 27 | val in = Flipped(new SimpleBusUC) 28 | val out = new SimpleBusUC 29 | }) 30 | 31 | io.out <> io.in 32 | val (regionBits, rebase) = (map._1, map._2.U(PAddrBits.W)) 33 | if (regionBits != 0) { 34 | io.out.req.bits.addr := Cat(rebase(PAddrBits-1, regionBits), io.in.req.bits.addr(regionBits-1, 0)) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/scala/bus/simplebus/DistributedMem.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package bus.simplebus 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | import chisel3.util.experimental.loadMemoryFromFile 22 | 23 | import nutcore.HasNutCoreParameter 24 | 25 | class DistributedMem(memByte: Int, dualPort: Boolean, delayCycles: Int = 0, dataFile: String = "") 26 | extends Module with HasNutCoreParameter { 27 | val io = IO(new Bundle { 28 | val rw = Flipped(new SimpleBusUC) 29 | val ro = Flipped(new SimpleBusUC) 30 | }) 31 | 32 | val wordNum = memByte / 8 33 | val nBank = XLEN / 8 34 | val memAddrBits = log2Up(wordNum) 35 | def Index(addr: UInt): UInt = addr(memAddrBits + 2 - 1, 2) 36 | 37 | val rwIdx = Index(io.rw.req.bits.addr) 38 | val roIdx = Index(io.ro.req.bits.addr) 39 | val wen = io.rw.isWrite 40 | val wdataVec = VecInit.tabulate(nBank) { i => io.rw.req.bits.wdata(8 * (i + 1) - 1, 8 * i) } 41 | val wmask = VecInit.tabulate(nBank) { i => io.rw.req.bits.wmask(i).asBool } 42 | 43 | val rwData = Wire(UInt(XLEN.W)) 44 | val roData = Wire(UInt(XLEN.W)) 45 | 46 | val mem = Mem(wordNum, Vec(nBank, UInt(8.W))) 47 | if (dataFile != "") 48 | loadMemoryFromFile(mem, dataFile) 49 | 50 | rwData := Cat(mem.read(rwIdx).reverse) 51 | roData := Cat(mem.read(roIdx).reverse) 52 | when (wen) { mem.write(rwIdx, wdataVec, wmask) } 53 | 54 | def readPort(p: SimpleBusUC, rdata: UInt) = { 55 | val s_idle :: s_reading :: Nil = Enum(2) 56 | val state = RegInit(s_idle) 57 | switch (state) { 58 | is (s_idle) { 59 | when (p.req.fire) { state := Mux(p.resp.fire, s_idle, s_reading) } 60 | } 61 | is (s_reading) { 62 | when (p.resp.fire) { state := s_idle } 63 | } 64 | } 65 | 66 | p.req.ready := state === s_idle 67 | p.resp.bits.rdata := rdata 68 | p.resp.valid := (if (delayCycles == 0) p.req.fire else Counter(state === s_reading, delayCycles)._2) 69 | } 70 | 71 | readPort(io.rw, rwData) 72 | if (dualPort) { 73 | readPort(io.ro, roData) 74 | } 75 | else { 76 | io.ro := DontCare 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/scala/bus/simplebus/SimpleBus.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package bus.simplebus 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | import nutcore.HasNutCoreParameter 23 | import utils._ 24 | import bus.axi4._ 25 | import bus.memport._ 26 | 27 | sealed abstract class SimpleBusBundle extends Bundle with HasNutCoreParameter 28 | 29 | object SimpleBusCmd { 30 | // req 31 | // hit | miss 32 | def read = "b0000".U // read | refill 33 | def write = "b0001".U // write | refill 34 | def readBurst = "b0010".U // read | refill 35 | def writeBurst = "b0011".U // write | refill 36 | def writeLast = "b0111".U // write | refill 37 | def probe = "b1000".U // read | do nothing 38 | def prefetch = "b0100".U // read | refill 39 | 40 | // resp 41 | def readLast = "b0110".U 42 | def writeResp = "b0101".U 43 | def probeHit = "b1100".U 44 | def probeMiss = "b1000".U 45 | 46 | def apply() = UInt(4.W) 47 | } 48 | 49 | class SimpleBusReqBundle(val userBits: Int = 0, val addrBits: Int = 32, val idBits: Int = 0) extends SimpleBusBundle { 50 | val addr = Output(UInt(addrBits.W)) 51 | val size = Output(UInt(3.W)) 52 | val cmd = Output(SimpleBusCmd()) 53 | val wmask = Output(UInt((DataBits / 8).W)) 54 | val wdata = Output(UInt(DataBits.W)) 55 | val user = if (userBits > 0) Some(Output(UInt(userBits.W))) else None 56 | val id = if (idBits > 0) Some(Output(UInt(idBits.W))) else None 57 | 58 | override def toPrintable: Printable = { 59 | p"addr = 0x${Hexadecimal(addr)}, cmd = ${cmd}, size = ${size}, " + 60 | p"wmask = 0x${Hexadecimal(wmask)}, wdata = 0x${Hexadecimal(wdata)}" 61 | } 62 | 63 | def apply(addr: UInt, cmd: UInt, size: UInt, wdata: UInt, wmask: UInt, user: UInt = 0.U, id: UInt = 0.U) = { 64 | this.addr := addr 65 | this.cmd := cmd 66 | this.size := size 67 | this.wdata := wdata 68 | this.wmask := wmask 69 | this.user.map(_ := user) 70 | this.id.map(_ := id) 71 | } 72 | 73 | def isRead() = !cmd(0) && !cmd(3) 74 | def isWrite() = cmd(0) 75 | def isBurst() = cmd(1) 76 | def isReadBurst() = cmd === SimpleBusCmd.readBurst 77 | def isWriteSingle() = cmd === SimpleBusCmd.write 78 | def isWriteLast() = cmd === SimpleBusCmd.writeLast 79 | def isProbe() = cmd === SimpleBusCmd.probe 80 | def isPrefetch() = cmd === SimpleBusCmd.prefetch 81 | } 82 | 83 | class SimpleBusRespBundle(val userBits: Int = 0, val idBits: Int = 0) extends SimpleBusBundle { 84 | val cmd = Output(SimpleBusCmd()) 85 | val rdata = Output(UInt(64.W)) // TODO: when frontend datapath support 32bit, set DataBits.W here 86 | val user = if (userBits > 0) Some(Output(UInt(userBits.W))) else None 87 | val id = if (idBits > 0) Some(Output(UInt(idBits.W))) else None 88 | 89 | override def toPrintable: Printable = p"rdata = ${Hexadecimal(rdata)}, cmd = ${cmd}" 90 | 91 | def isReadLast = cmd === SimpleBusCmd.readLast 92 | def isProbeHit = cmd === SimpleBusCmd.probeHit 93 | def isProbeMiss = cmd === SimpleBusCmd.probeMiss 94 | def isWriteResp = cmd === SimpleBusCmd.writeResp 95 | def isPrefetch = cmd === SimpleBusCmd.prefetch 96 | } 97 | 98 | // Uncache 99 | class SimpleBusUC(val userBits: Int = 0, val addrBits: Int = 32, val idBits: Int = 0) extends SimpleBusBundle { 100 | val req = Decoupled(new SimpleBusReqBundle(userBits, addrBits, idBits)) 101 | val resp = Flipped(Decoupled(new SimpleBusRespBundle(userBits, idBits))) 102 | 103 | def isWrite = req.valid && req.bits.isWrite() 104 | def isRead = req.valid && req.bits.isRead() 105 | def toAXI4Lite = SimpleBus2AXI4Converter(this, new AXI4Lite, false) 106 | def toAXI4(isFromCache: Boolean = false) = SimpleBus2AXI4Converter(this, new AXI4, isFromCache) 107 | def toMemPort = SimpleBus2MemPortConverter(this, new MemPortIo(32)) 108 | 109 | def dump(name: String) = { 110 | when (req.fire) { printf(p"${GTimer()},[${name}] ${req.bits}\n") } 111 | when (resp.fire) { printf(p"${GTimer()},[${name}] ${resp.bits}\n") } 112 | } 113 | } 114 | 115 | class SimpleBusUCExpender(val userBits: Int, val userVal: UInt, val addrBits: Int = 32, idBits: Int = 0) extends Module { 116 | val io = IO(new Bundle{ 117 | val in = Flipped(new SimpleBusUC()) 118 | val out = new SimpleBusUC(userBits = userBits, idBits = idBits) 119 | }) 120 | require(userBits > 0) 121 | io.out.req.valid := io.in.req.valid 122 | io.in.req.ready := io.out.req.ready 123 | io.out.req.bits.addr := io.in.req.bits.addr 124 | io.out.req.bits.size := io.in.req.bits.size 125 | io.out.req.bits.cmd := io.in.req.bits.cmd 126 | io.out.req.bits.wmask := io.in.req.bits.wmask 127 | io.out.req.bits.wdata := io.in.req.bits.wdata 128 | io.out.req.bits.user.get := userVal 129 | io.in.resp.valid := io.out.resp.valid 130 | io.out.resp.ready := io.in.resp.ready 131 | io.in.resp.bits.cmd := io.out.resp.bits.cmd 132 | io.in.resp.bits.rdata := io.out.resp.bits.rdata 133 | // DontCare := io.out.resp.bits.user.get 134 | } 135 | 136 | // Cache 137 | class SimpleBusC(val userBits: Int = 0) extends SimpleBusBundle { 138 | val mem = new SimpleBusUC(userBits) 139 | val coh = Flipped(new SimpleBusUC(userBits)) 140 | 141 | def memtoMemPort() = this.mem.toMemPort 142 | } 143 | -------------------------------------------------------------------------------- /src/main/scala/bus/simplebus/ToMemPort.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package bus.simplebus 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | import bus.memport._ 23 | import utils._ 24 | import bus.memport.MemoryOpConstants 25 | 26 | object MemPortConsts extends MemoryOpConstants{} 27 | 28 | class SimpleBus2MemPortConverter(outType: MemPortIo) extends Module { 29 | val io = IO(new Bundle { 30 | val in = Flipped(new SimpleBusUC) 31 | val out = Flipped(Flipped(outType)) 32 | }) 33 | 34 | io.in.req.ready := io.out.req.ready 35 | io.in.resp.valid := io.out.resp.valid 36 | io.out.req.valid := io.in.req.valid 37 | io.out.resp.ready := io.in.resp.ready 38 | 39 | io.out.req.bits.addr := io.in.req.bits.addr 40 | io.out.req.bits.data := io.in.req.bits.wdata 41 | io.out.req.bits.fcn := Mux(io.in.req.bits.isRead(), MemPortConsts.M_XRD, MemPortConsts.M_XWR) 42 | io.out.req.bits.typ := MemPortConsts.MT_W 43 | 44 | io.in.resp.bits.rdata := io.out.resp.bits.data 45 | io.in.resp.bits.cmd := SimpleBusCmd.readLast 46 | } 47 | 48 | object SimpleBus2MemPortConverter { 49 | def apply(in: SimpleBusUC, outType: MemPortIo): MemPortIo = { 50 | val bridge = Module(new SimpleBus2MemPortConverter(outType)) 51 | bridge.io.in <> in 52 | bridge.io.out 53 | } 54 | } -------------------------------------------------------------------------------- /src/main/scala/device/AXI4CLINT.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package device 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | import chisel3.util.experimental.BoringUtils 22 | 23 | import bus.axi4._ 24 | import utils._ 25 | 26 | class ClintIO extends Bundle { 27 | val mtip = Output(Bool()) 28 | val msip = Output(Bool()) 29 | } 30 | 31 | class AXI4CLINT(sim: Boolean = false) extends AXI4SlaveModule(new AXI4Lite, new ClintIO) { 32 | val mtime = RegInit(0.U(64.W)) // unit: us 33 | val mtimecmp = RegInit(0.U(64.W)) 34 | val msip = RegInit(0.U(64.W)) 35 | 36 | val clk = (if (!sim) 40 /* 40MHz / 1000000 */ else 10000) 37 | val freq_reg = RegInit(clk.U(64.W)) 38 | val freq = freq_reg(15, 0) 39 | val inc_reg = RegInit(1.U(64.W)) 40 | val inc = inc_reg(15, 0) 41 | 42 | val cnt = RegInit(0.U(16.W)) 43 | val nextCnt = cnt + 1.U 44 | cnt := Mux(nextCnt < freq, nextCnt, 0.U) 45 | val tick = (nextCnt === freq) 46 | when (tick) { mtime := mtime + inc } 47 | 48 | if (sim) { 49 | val isWFI = WireInit(false.B) 50 | BoringUtils.addSink(isWFI, "isWFI") 51 | when (isWFI) { mtime := mtime + 100000.U } 52 | } 53 | 54 | val mapping = Map( 55 | RegMap(0x0, msip), 56 | RegMap(0x4000, mtimecmp), 57 | RegMap(0x8000, freq_reg), 58 | RegMap(0x8008, inc_reg), 59 | RegMap(0xbff8, mtime) 60 | ) 61 | def getOffset(addr: UInt) = addr(15,0) 62 | 63 | RegMap.generate(mapping, getOffset(raddr), in.r.bits.data, 64 | getOffset(waddr), in.w.fire, in.w.bits.data, MaskExpand(in.w.bits.strb)) 65 | 66 | io.extra.get.mtip := RegNext(mtime >= mtimecmp) 67 | io.extra.get.msip := RegNext(msip =/= 0.U) 68 | } 69 | -------------------------------------------------------------------------------- /src/main/scala/device/AXI4DMA.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package device 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | import bus.axi4._ 23 | import utils._ 24 | 25 | class DMABundle extends Bundle { 26 | val dma = new AXI4 27 | } 28 | 29 | class AXI4DMA extends AXI4SlaveModule(new AXI4Lite, new DMABundle) { 30 | val step = 4 // unit: byte. step = 8 is not supported now. 31 | val stepBits = step * 8 32 | val autoStart = false 33 | 34 | val dest = Reg(UInt(32.W)) 35 | val src = Reg(UInt(32.W)) 36 | val len = RegInit(0.U(32.W)) 37 | 38 | val dma = io.extra.get.dma 39 | val data = Reg(UInt(stepBits.W)) 40 | 41 | val s_idle :: s_read_req :: s_read_wait_resp :: s_write_req :: s_write_wait_resp :: Nil = Enum(5) 42 | val state = RegInit(s_idle) 43 | 44 | if (autoStart) { 45 | when (state === s_idle && len === 0.U) { 46 | len := 32768.U 47 | dest := "h62000000".U 48 | src := "h62000000".U 49 | printf("\n@") 50 | } 51 | } 52 | when (state === s_idle && len =/= 0.U) { state := s_read_req } 53 | when (state === s_read_req && dma.ar.fire) { state := s_read_wait_resp } 54 | when (state === s_read_wait_resp && dma.r.fire) { 55 | data := dma.r.bits.data.asTypeOf(Vec(8 / step, UInt(stepBits.W)))(src(2, log2Ceil(step))) 56 | state := s_write_req 57 | } 58 | 59 | val wSend = Wire(Bool()) 60 | val wlast = dma.w.bits.last 61 | val awAck = BoolStopWatch(dma.aw.fire, wSend) 62 | val wAck = BoolStopWatch(dma.w.fire && wlast, wSend) 63 | wSend := (dma.aw.fire && dma.w.fire && wlast) || (awAck && wAck) 64 | 65 | when (state === s_write_req && wSend) { state := s_write_wait_resp } 66 | when (state === s_write_wait_resp && dma.b.fire) { 67 | len := len - step.U 68 | dest := dest + step.U 69 | src := src + step.U 70 | state := Mux(len <= step.U, s_idle, s_read_req) 71 | } 72 | 73 | dma.ar.bits.prot := AXI4Parameters.PROT_PRIVILEGED 74 | dma.ar.bits.id := 0.U 75 | dma.ar.bits.size := log2Ceil(step).U 76 | dma.ar.bits.burst := AXI4Parameters.BURST_INCR 77 | dma.ar.bits.lock := false.B 78 | dma.ar.bits.cache := 0.U 79 | dma.ar.bits.qos := 0.U 80 | dma.ar.bits.user := 0.U 81 | dma.ar.bits.len := 0.U 82 | dma.ar.bits.addr := src 83 | dma.ar.valid := (state === s_read_req) 84 | dma.r.ready := (state === s_read_wait_resp) 85 | 86 | dma.aw.bits := dma.ar.bits 87 | dma.aw.bits.addr := dest 88 | dma.aw.valid := (state === s_write_req) && !awAck 89 | dma.w.valid := (state === s_write_req) && !wAck 90 | dma.w.bits.data := Fill(8 / step, data) 91 | dma.w.bits.strb := Fill(step, "b1".U) << (dest(2,log2Ceil(step)) * step.U) 92 | dma.w.bits.last := true.B 93 | dma.b.ready := (state === s_write_wait_resp) 94 | 95 | val mapping = Map( 96 | RegMap(0x0, dest), 97 | RegMap(0x4, src), 98 | RegMap(0x8, len) 99 | ) 100 | 101 | RegMap.generate(mapping, raddr(3,0), in.r.bits.data, 102 | waddr(3,0), in.w.fire, in.w.bits.data(31, 0), MaskExpand(in.w.bits.strb >> waddr(2, 0))(31, 0) 103 | ) 104 | } 105 | -------------------------------------------------------------------------------- /src/main/scala/device/AXI4DummySD.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package device 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | import bus.axi4._ 23 | import utils._ 24 | 25 | trait HasSDConst { 26 | def MemorySize = 4L * 1024 * 1024 * 1024 // 4GB 27 | def READ_BL_LEN = 15 28 | def BlockLen = (1 << READ_BL_LEN) 29 | def NrBlock = MemorySize / BlockLen 30 | def C_SIZE_MULT = 7 // only 3 bits 31 | def MULT = (1 << (C_SIZE_MULT + 2)) 32 | def C_SIZE = NrBlock / MULT - 1 33 | } 34 | 35 | class SDHelper extends BlackBox with HasBlackBoxInline { 36 | val io = IO(new Bundle { 37 | val clk = Input(Clock()) 38 | val ren = Input(Bool()) 39 | val data = Output(UInt(32.W)) 40 | val setAddr = Input(Bool()) 41 | val addr = Input(UInt(32.W)) 42 | }).suggestName("io") 43 | 44 | setInline("SDHelper.v", 45 | s""" 46 | |import "DPI-C" function void sd_setaddr(input int addr); 47 | |import "DPI-C" function void sd_read(output int data); 48 | | 49 | |module SDHelper ( 50 | | input clk, 51 | | input setAddr, 52 | | input [31:0] addr, 53 | | input ren, 54 | | output reg [31:0] data 55 | |); 56 | | 57 | | always @(negedge clk) begin 58 | | if (ren) sd_read(data); 59 | | end 60 | | always@(posedge clk) begin 61 | | if (setAddr) sd_setaddr(addr); 62 | | end 63 | | 64 | |endmodule 65 | """.stripMargin) 66 | } 67 | 68 | class AXI4DummySD extends AXI4SlaveModule(new AXI4Lite) with HasSDConst { 69 | val range = List.range(0,21) 70 | val sdcmd :: sdarg :: sdtout :: sdcdiv :: sdrsp0 :: sdrsp1 :: sdrsp2 :: sdrsp3 :: sdhsts :: __pad0 :: __pad1 :: __pad2 :: sdvdd :: sdedm :: sdhcfg :: sdhbct :: sddata :: __pad10 :: __pad11 :: __pad12 :: sdhblc :: Nil = range 71 | 72 | val regs = List.fill(range.size)(RegInit(0.U(32.W))) 73 | val edmConst = (8 << 4).U // number of data in fifo 74 | 75 | val MMC_SEND_OP_COND = 1 76 | val MMC_ALL_SEND_CID = 2 77 | val MMC_SEND_CSD = 9 78 | val MMC_SEND_STATUS = 13 79 | val MMC_READ_MULTIPLE_BLOCK = 18 80 | 81 | val setAddr = WireInit(false.B) 82 | 83 | def cmdWfn(wdata: UInt) = { 84 | val cmd = wdata(5,0) 85 | switch (cmd) { 86 | is (MMC_SEND_OP_COND.U) { 87 | regs(sdrsp0) := "h80ff8000".U 88 | } 89 | is (MMC_ALL_SEND_CID.U) { 90 | regs(sdrsp0) := "h00000001".U 91 | regs(sdrsp1) := "h00000000".U 92 | regs(sdrsp2) := "h00000000".U 93 | regs(sdrsp3) := "h15000000".U 94 | } 95 | is (MMC_SEND_CSD.U) { 96 | regs(sdrsp0) := "h92404001".U 97 | regs(sdrsp1) := "h124b97e3".U | (C_SIZE.U(1,0) << 30) 98 | regs(sdrsp2) := "h0f508000".U | C_SIZE.U(11,2) | (READ_BL_LEN.U << 16) 99 | regs(sdrsp3) := "h8c26012a".U 100 | } 101 | is (MMC_SEND_STATUS.U) { 102 | regs(sdrsp0) := 0.U 103 | regs(sdrsp1) := 0.U 104 | regs(sdrsp2) := 0.U 105 | regs(sdrsp3) := 0.U 106 | } 107 | is (MMC_READ_MULTIPLE_BLOCK.U) { 108 | setAddr := true.B 109 | } 110 | } 111 | wdata 112 | } 113 | 114 | val sdHelper = Module(new SDHelper) 115 | sdHelper.io.clk := clock 116 | sdHelper.io.ren := (getOffset(raddr) === 0x40.U && io.in.ar.fire) 117 | sdHelper.io.setAddr := setAddr 118 | sdHelper.io.addr := regs(sdarg) 119 | def sdRead = sdHelper.io.data 120 | 121 | val mapping = Map( 122 | RegMap(0x00, regs(sdcmd), cmdWfn), 123 | RegMap(0x04, regs(sdarg)), 124 | RegMap(0x10, regs(sdrsp0), RegMap.Unwritable), 125 | RegMap(0x14, regs(sdrsp1), RegMap.Unwritable), 126 | RegMap(0x18, regs(sdrsp2), RegMap.Unwritable), 127 | RegMap(0x1c, regs(sdrsp3), RegMap.Unwritable), 128 | RegMap(0x20, regs(sdhsts)), 129 | RegMap(0x34, edmConst, RegMap.Unwritable), 130 | RegMap(0x38, regs(sdhcfg)), 131 | RegMap(0x38, regs(sdhbct)), 132 | RegMap(0x40, sdRead, RegMap.Unwritable), 133 | RegMap(0x50, regs(sdhblc)) 134 | ) 135 | def getOffset(addr: UInt) = addr(12,0) 136 | 137 | val strb = if (DataBits == 32) in.w.bits.strb(3,0) 138 | else Mux(waddr(2), in.w.bits.strb(7,4), in.w.bits.strb(3,0)) 139 | val rdata = Wire(UInt(DataBits.W)) 140 | RegMap.generate(mapping, getOffset(raddr), rdata, 141 | getOffset(waddr), in.w.fire, in.w.bits.data(31, 0), MaskExpand(strb)) 142 | 143 | in.r.bits.data := (if (DataBits == 32) RegEnable(RegNext(rdata(31,0)), ren) 144 | else RegEnable(RegNext(Fill(2, rdata(31,0))), ren)) 145 | } 146 | -------------------------------------------------------------------------------- /src/main/scala/device/AXI4Flash.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package device 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | import bus.axi4._ 23 | import utils._ 24 | 25 | class AXI4Flash extends AXI4SlaveModule(new AXI4Lite) { 26 | val jmpToDramInstr1 = "h0010029b".U // addiw t0,zero,1 27 | val jmpToDramInstr2 = "h01f29293".U // slli t0,t0,0x1f 28 | val jmpToDramInstr3 = "h00028067".U // jr t0 29 | 30 | val mapping = Map( 31 | RegMap(0x0, jmpToDramInstr1, RegMap.Unwritable), 32 | RegMap(0x4, jmpToDramInstr2, RegMap.Unwritable), 33 | RegMap(0x8, jmpToDramInstr3, RegMap.Unwritable) 34 | ) 35 | def getOffset(addr: UInt) = addr(12,0) 36 | 37 | val rdata = Wire(UInt(64.W)) 38 | RegMap.generate(mapping, getOffset(raddr), rdata, 39 | getOffset(waddr), in.w.fire, in.w.bits.data, MaskExpand(in.w.bits.strb)) 40 | 41 | in.r.bits.data := RegEnable(RegNext(Fill(2, rdata(31,0))), ren) 42 | } 43 | -------------------------------------------------------------------------------- /src/main/scala/device/AXI4Keyboard.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package device 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | import bus.axi4._ 23 | import utils._ 24 | 25 | class KeyboardIO extends Bundle { 26 | val ps2Clk = Input(Bool()) 27 | val ps2Data = Input(Bool()) 28 | } 29 | 30 | // this Module is not tested 31 | class AXI4Keyboard extends AXI4SlaveModule(new AXI4Lite, new KeyboardIO) { 32 | val buf = Reg(UInt(10.W)) 33 | val ps2ClkLatch = RegNext(io.extra.get.ps2Clk) 34 | val negedge = RegNext(ps2ClkLatch) && ~ps2ClkLatch 35 | when (negedge) { buf := Cat(io.extra.get.ps2Data, buf(9,1)) } 36 | 37 | val cnt = Counter(negedge, 10) 38 | val queue = Module(new Queue(UInt(8.W), 8)) 39 | queue.io.enq.valid := cnt._2 && !buf(0) && io.extra.get.ps2Data && buf(9,1).xorR 40 | queue.io.enq.bits := buf(8,1) 41 | queue.io.deq.ready := in.r.ready 42 | 43 | in.r.bits.data := Mux(queue.io.deq.valid, queue.io.deq.bits, 0.U) 44 | } 45 | -------------------------------------------------------------------------------- /src/main/scala/device/AXI4PLIC.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package device 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | import bus.axi4._ 23 | import utils._ 24 | 25 | class PlicIO(val nrIntr: Int, val nrHart: Int) extends Bundle { 26 | val intrVec = Input(UInt(nrIntr.W)) 27 | val meip = Output(Vec(nrHart, Bool())) 28 | } 29 | 30 | class AXI4PLIC(nrIntr: Int, nrHart: Int) extends AXI4SlaveModule(new AXI4Lite, new PlicIO(nrIntr, nrHart)) { 31 | require(nrIntr < 1024) 32 | require(nrHart <= 15872) 33 | val addressSpaceSize = 0x4000000 34 | val addressBits = log2Up(addressSpaceSize) 35 | def getOffset(addr: UInt) = addr(addressBits-1,0) 36 | 37 | val priority = List.fill(nrIntr)(Reg(UInt(32.W))) 38 | val priorityMap = priority.zipWithIndex.map{ case (r, intr) => RegMap((intr + 1) * 4, r) }.toMap 39 | 40 | val nrIntrWord = (nrIntr + 31) / 32 // roundup 41 | // pending bits are updated in the unit of bit by PLIC, 42 | // so define it as vectors of bits, instead of UInt(32.W) 43 | val pending = List.fill(nrIntrWord)(RegInit(0.U.asTypeOf(Vec(32, Bool())))) 44 | val pendingMap = pending.zipWithIndex.map { case (r, intrWord) => 45 | RegMap(0x1000 + intrWord * 4, Cat(r.reverse), RegMap.Unwritable) 46 | }.toMap 47 | 48 | val enable = List.fill(nrHart)( List.fill(nrIntrWord)(RegInit(0.U(32.W))) ) 49 | val enableMap = enable.zipWithIndex.map { case (l, hart) => 50 | l.zipWithIndex.map { case (r, intrWord) => RegMap(0x2000 + hart * 0x80 + intrWord * 4, r) } 51 | }.reduce(_ ++ _).toMap 52 | 53 | val threshold = List.fill(nrHart)(Reg(UInt(32.W))) 54 | val thresholdMap = threshold.zipWithIndex.map { 55 | case (r, hart) => RegMap(0x200000 + hart * 0x1000, r) 56 | }.toMap 57 | 58 | val inHandle = RegInit(0.U.asTypeOf(Vec(nrIntr + 1, Bool()))) 59 | def completionFn(wdata: UInt) = { 60 | inHandle(wdata(31,0)) := false.B 61 | 0.U 62 | } 63 | 64 | val claimCompletion = List.fill(nrHart)(Reg(UInt(32.W))) 65 | val claimCompletionMap = claimCompletion.zipWithIndex.map { 66 | case (r, hart) => { 67 | val addr = 0x200004 + hart * 0x1000 68 | when (in.r.fire && (getOffset(raddr) === addr.U)) { inHandle(r) := true.B } 69 | RegMap(addr, r, completionFn) 70 | } 71 | }.toMap 72 | 73 | io.extra.get.intrVec.asBools.zipWithIndex.map { case (intr, i) => { 74 | val id = i + 1 75 | when (intr) { pending(id / 32)(id % 32) := true.B } 76 | when (inHandle(id)) { pending(id / 32)(id % 32) := false.B } 77 | } } 78 | 79 | val pendingVec = Cat(pending.map(x => Cat(x.reverse))) 80 | claimCompletion.zipWithIndex.map { case (r, hart) => { 81 | val takenVec = pendingVec & Cat(enable(hart)) 82 | r := Mux(takenVec === 0.U, 0.U, PriorityEncoder(takenVec)) 83 | } } 84 | 85 | val mapping = priorityMap ++ pendingMap ++ enableMap ++ thresholdMap ++ claimCompletionMap 86 | 87 | val rdata = Wire(UInt(32.W)) 88 | RegMap.generate(mapping, getOffset(raddr), rdata, 89 | getOffset(waddr), in.w.fire, in.w.bits.data(31, 0), 90 | MaskExpand(in.w.bits.strb >> waddr(2,0))(31, 0) 91 | ) 92 | // narrow read 93 | in.r.bits.data := Fill(2, rdata) 94 | 95 | io.extra.get.meip.zipWithIndex.map { case (ip, hart) => ip := claimCompletion(hart) =/= 0.U } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/scala/device/AXI4RAM.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package device 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | import nutcore.HasNutCoreParameter 23 | import bus.axi4._ 24 | import difftest.common.DifftestMem 25 | 26 | class AXI4RAM[T <: AXI4Lite](_type: T = new AXI4, memByte: Long, 27 | useBlackBox: Boolean = false) extends AXI4SlaveModule(_type) with HasNutCoreParameter { 28 | 29 | def index(addr: UInt) = addr(log2Ceil(memByte) - 1, log2Ceil(DataBytes)) 30 | def inRange(idx: UInt) = idx < (memByte / 8).U 31 | 32 | val wIdx = index(waddr) + writeBeatCnt 33 | val rIdx = index(raddr) + readBeatCnt 34 | val wen = in.w.fire && inRange(wIdx) 35 | 36 | val rdata = if (useBlackBox) { 37 | val mem = DifftestMem(memByte, 8) 38 | when (wen) { 39 | mem.write( 40 | addr = wIdx, 41 | data = in.w.bits.data.asTypeOf(Vec(DataBytes, UInt(8.W))), 42 | mask = in.w.bits.strb.asBools 43 | ) 44 | } 45 | mem.readAndHold(rIdx, ren).asUInt 46 | } else { 47 | val mem = Mem(memByte / DataBytes, Vec(DataBytes, UInt(8.W))) 48 | 49 | val wdata = VecInit.tabulate(DataBytes) { i => in.w.bits.data(8*(i+1)-1, 8*i) } 50 | when (wen) { mem.write(wIdx, wdata, in.w.bits.strb.asBools) } 51 | 52 | RegEnable(Cat(mem.read(rIdx).reverse), ren) 53 | } 54 | 55 | in.r.bits.data := rdata 56 | } 57 | -------------------------------------------------------------------------------- /src/main/scala/device/AXI4Slave.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package device 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | import nutcore.HasNutCoreParameter 23 | import bus.axi4._ 24 | import utils._ 25 | 26 | abstract class AXI4SlaveModule[T <: AXI4Lite, B <: Data](_type :T = new AXI4, _extra: B = null) 27 | extends Module with HasNutCoreParameter { 28 | val io = IO(new Bundle{ 29 | val in = Flipped(_type) 30 | val extra = if (_extra != null) Some(Flipped(Flipped(_extra))) else None 31 | }) 32 | val in = io.in 33 | 34 | val fullMask = MaskExpand(in.w.bits.strb) 35 | def genWdata(originData: UInt) = (originData & ~fullMask) | (in.w.bits.data & fullMask) 36 | 37 | val raddr = Wire(UInt()) 38 | val ren = Wire(Bool()) 39 | val (readBeatCnt, rLast) = in match { 40 | case axi4: AXI4 => 41 | val c = Counter(256) 42 | val beatCnt = Counter(256) 43 | val len = HoldUnless(axi4.ar.bits.len, axi4.ar.fire) 44 | val burst = HoldUnless(axi4.ar.bits.burst, axi4.ar.fire) 45 | val wrapAddr = axi4.ar.bits.addr & ~(axi4.ar.bits.len.asTypeOf(UInt(PAddrBits.W)) << axi4.ar.bits.size) 46 | raddr := HoldUnless(wrapAddr, axi4.ar.fire) 47 | axi4.r.bits.last := (c.value === len) 48 | when (ren) { 49 | beatCnt.inc() 50 | when (burst === AXI4Parameters.BURST_WRAP && beatCnt.value === len) { beatCnt.value := 0.U } 51 | } 52 | when (axi4.r.fire) { 53 | c.inc() 54 | when (axi4.r.bits.last) { c.value := 0.U } 55 | } 56 | when (axi4.ar.fire) { 57 | beatCnt.value := (axi4.ar.bits.addr >> axi4.ar.bits.size) & axi4.ar.bits.len 58 | when (axi4.ar.bits.len =/= 0.U && axi4.ar.bits.burst === AXI4Parameters.BURST_WRAP) { 59 | assert(axi4.ar.bits.len === 1.U || axi4.ar.bits.len === 3.U || 60 | axi4.ar.bits.len === 7.U || axi4.ar.bits.len === 15.U) 61 | } 62 | } 63 | (beatCnt.value, axi4.r.bits.last) 64 | 65 | case axi4lite: AXI4Lite => 66 | raddr := axi4lite.ar.bits.addr 67 | (0.U, true.B) 68 | } 69 | 70 | val r_busy = BoolStopWatch(in.ar.fire, in.r.fire && rLast, startHighPriority = true) 71 | in.ar.ready := in.r.ready || !r_busy 72 | in.r.bits.resp := AXI4Parameters.RESP_OKAY 73 | ren := RegNext(in.ar.fire, init=false.B) || (in.r.fire && !rLast) 74 | in.r.valid := BoolStopWatch(ren && (in.ar.fire || r_busy), in.r.fire, startHighPriority = true) 75 | 76 | 77 | val waddr = Wire(UInt()) 78 | val (writeBeatCnt, wLast) = in match { 79 | case axi4: AXI4 => 80 | val c = Counter(256) 81 | waddr := HoldUnless(axi4.aw.bits.addr, axi4.aw.fire) 82 | when (axi4.w.fire) { 83 | c.inc() 84 | when (axi4.w.bits.last) { c.value := 0.U } 85 | } 86 | (c.value, axi4.w.bits.last) 87 | 88 | case axi4lite: AXI4Lite => 89 | waddr := axi4lite.aw.bits.addr 90 | (0.U, true.B) 91 | } 92 | 93 | val w_busy = BoolStopWatch(in.aw.fire, in.b.fire, startHighPriority = true) 94 | in.aw.ready := !w_busy 95 | in. w.ready := in.aw.valid || (w_busy) 96 | in.b.bits.resp := AXI4Parameters.RESP_OKAY 97 | in.b.valid := BoolStopWatch(in.w.fire && wLast, in.b.fire, startHighPriority = true) 98 | 99 | in match { 100 | case axi4: AXI4 => 101 | axi4.b.bits.id := RegEnable(axi4.aw.bits.id, axi4.aw.fire) 102 | axi4.b.bits.user := RegEnable(axi4.aw.bits.user, axi4.aw.fire) 103 | axi4.r.bits.id := RegEnable(axi4.ar.bits.id, axi4.ar.fire) 104 | axi4.r.bits.user := RegEnable(axi4.ar.bits.user, axi4.ar.fire) 105 | case axi4lite: AXI4Lite => 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/scala/device/AXI4UART.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package device 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | import bus.axi4._ 23 | import utils._ 24 | import difftest._ 25 | 26 | class AXI4UART extends AXI4SlaveModule(new AXI4Lite, _extra = new UARTIO) 27 | { 28 | val rxfifo = RegInit(0.U(32.W)) 29 | val txfifo = Reg(UInt(32.W)) 30 | val stat = RegInit(1.U(32.W)) 31 | val ctrl = RegInit(0.U(32.W)) 32 | 33 | io.extra.get.out.valid := (waddr(3,0) === 4.U && in.w.fire) 34 | io.extra.get.out.ch := in.w.bits.data(7,0) 35 | io.extra.get.in.valid := (raddr(3,0) === 0.U && in.r.fire) 36 | 37 | val mapping = Map( 38 | RegMap(0x0, io.extra.get.in.ch, RegMap.Unwritable), 39 | RegMap(0x4, txfifo), 40 | RegMap(0x8, stat), 41 | RegMap(0xc, ctrl) 42 | ) 43 | 44 | RegMap.generate(mapping, raddr(3,0), in.r.bits.data, 45 | waddr(3,0), in.w.fire, in.w.bits.data(31, 0), MaskExpand(in.w.bits.strb >> waddr(2, 0))(31, 0) 46 | ) 47 | } 48 | -------------------------------------------------------------------------------- /src/main/scala/nutcore/Bundle.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package nutcore 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | class CtrlSignalIO extends NutCoreBundle { 23 | val src1Type = Output(SrcType()) 24 | val src2Type = Output(SrcType()) 25 | val fuType = Output(FuType()) 26 | val fuOpType = Output(FuOpType()) 27 | val rfSrc1 = Output(UInt(5.W)) 28 | val rfSrc2 = Output(UInt(5.W)) 29 | val rfWen = Output(Bool()) 30 | val rfDest = Output(UInt(5.W)) 31 | val isNutCoreTrap = Output(Bool()) 32 | val isSrc1Forward = Output(Bool()) 33 | val isSrc2Forward = Output(Bool()) 34 | val noSpecExec = Output(Bool()) // This inst can not be speculated 35 | val isBlocked = Output(Bool()) // This inst requires pipeline to be blocked 36 | } 37 | 38 | class DataSrcIO extends NutCoreBundle { 39 | val src1 = Output(UInt(XLEN.W)) 40 | val src2 = Output(UInt(XLEN.W)) 41 | val imm = Output(UInt(XLEN.W)) 42 | } 43 | 44 | class RedirectIO extends NutCoreBundle { 45 | val target = Output(UInt(VAddrBits.W)) 46 | val rtype = Output(UInt(1.W)) // 1: branch mispredict: only need to flush frontend 0: others: flush the whole pipeline 47 | val valid = Output(Bool()) 48 | } 49 | 50 | class MisPredictionRecIO extends NutCoreBundle { 51 | val redirect = new RedirectIO 52 | val valid = Output(Bool()) 53 | val checkpoint = Output(UInt(brTagWidth.W)) 54 | val prfidx = Output(UInt(prfAddrWidth.W)) 55 | } 56 | 57 | class CtrlFlowIO extends NutCoreBundle { 58 | val instr = Output(UInt(64.W)) 59 | val pc = Output(UInt(VAddrBits.W)) 60 | val pnpc = Output(UInt(VAddrBits.W)) 61 | val redirect = new RedirectIO 62 | val exceptionVec = Output(Vec(16, Bool())) 63 | val intrVec = Output(Vec(12, Bool())) 64 | val brIdx = Output(UInt(4.W)) 65 | val isRVC = Output(Bool()) 66 | val crossPageIPFFix = Output(Bool()) 67 | val runahead_checkpoint_id = Output(UInt(64.W)) 68 | val isBranch = Output(Bool()) 69 | } 70 | 71 | class DecodeIO extends NutCoreBundle { 72 | val cf = new CtrlFlowIO 73 | val ctrl = new CtrlSignalIO 74 | val data = new DataSrcIO 75 | } 76 | 77 | class WriteBackIO extends NutCoreBundle { 78 | val rfWen = Output(Bool()) 79 | val rfDest = Output(UInt(5.W)) 80 | val rfData = Output(UInt(XLEN.W)) 81 | } 82 | 83 | class CommitIO extends NutCoreBundle { 84 | val decode = new DecodeIO 85 | val isMMIO = Output(Bool()) 86 | val intrNO = Output(UInt(XLEN.W)) 87 | val commits = Output(Vec(FuType.num, UInt(XLEN.W))) 88 | } 89 | 90 | class OOCommitIO extends NutCoreBundle with HasBackendConst{ 91 | val decode = new DecodeIO 92 | val isMMIO = Output(Bool()) 93 | val intrNO = Output(UInt(XLEN.W)) 94 | val commits = Output(UInt(XLEN.W)) 95 | val prfidx = Output(UInt(prfAddrWidth.W)) //also as robidx 96 | val exception = Output(Bool()) 97 | val store = Output(Bool()) 98 | val brMask = Output(UInt(checkpointSize.W)) 99 | } 100 | 101 | class FunctionUnitIO extends NutCoreBundle { 102 | val in = Flipped(Decoupled(new Bundle { 103 | val src1 = Output(UInt(XLEN.W)) 104 | val src2 = Output(UInt(XLEN.W)) 105 | val func = Output(FuOpType()) 106 | })) 107 | val out = Decoupled(Output(UInt(XLEN.W))) 108 | } 109 | 110 | class ForwardIO extends NutCoreBundle { 111 | val valid = Output(Bool()) 112 | val wb = new WriteBackIO 113 | val fuType = Output(FuType()) 114 | } 115 | 116 | class MMUIO extends NutCoreBundle { 117 | // val ptev = Output(Bool()) 118 | // val pteu = Output(Bool()) 119 | // val ptex = Output(Bool()) 120 | // val valid = Output(Bool()) 121 | // val isStore = Output(Bool()) 122 | 123 | val privilegeMode = Input(UInt(2.W)) 124 | val status_sum = Input(Bool()) 125 | val status_mxr = Input(Bool()) 126 | 127 | val loadPF = Output(Bool()) 128 | val storePF = Output(Bool()) 129 | val addr = Output(UInt(VAddrBits.W)) 130 | 131 | def isPF() = loadPF || storePF 132 | } 133 | 134 | class MemMMUIO extends NutCoreBundle { 135 | val imem = new MMUIO 136 | val dmem = new MMUIO 137 | } 138 | 139 | class TLBExuIO extends NutCoreBundle { 140 | val satp = Output(UInt(XLEN.W)) 141 | val sfence = new Bundle { 142 | val valid = Output(Bool()) 143 | val asid = Output(UInt(9.W)) 144 | val vaddr = Output(UInt(XLEN.W)) 145 | } 146 | 147 | def access(valid: Bool, src1: UInt, src2: UInt, func: UInt, satp: UInt) = {//func no use here for just sfence.vma only 148 | this.sfence.valid := valid 149 | this.sfence.vaddr := src1 150 | this.sfence.asid := src2(8,0) 151 | this.satp := satp 152 | } 153 | } 154 | 155 | class InstFetchIO extends NutCoreBundle { 156 | val pc = Output(UInt(VAddrBits.W)) // real PC will be regenerated in IBF 157 | val pnpc = Output(UInt(VAddrBits.W)) 158 | val brIdx = Output(UInt(4.W)) 159 | val instValid = Output(UInt(4.W)) 160 | //above will be used as user bits in icache 161 | val icachePF = Output(Bool()) 162 | val instr = Output(UInt(64.W)) 163 | } 164 | 165 | // Micro OP 166 | class RenamedDecodeIO extends NutCoreBundle with HasBackendConst { 167 | val decode = new DecodeIO 168 | val prfDest = Output(UInt(prfAddrWidth.W)) 169 | val prfSrc1 = Output(UInt(prfAddrWidth.W)) 170 | val prfSrc2 = Output(UInt(prfAddrWidth.W)) 171 | val src1Rdy = Output(Bool()) 172 | val src2Rdy = Output(Bool()) 173 | val brMask = Output(UInt(checkpointSize.W)) 174 | } -------------------------------------------------------------------------------- /src/main/scala/nutcore/Decode.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package nutcore 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | trait HasInstrType { 23 | def InstrN = "b0000".U 24 | def InstrI = "b0100".U 25 | def InstrR = "b0101".U 26 | def InstrS = "b0010".U 27 | def InstrB = "b0001".U 28 | def InstrU = "b0110".U 29 | def InstrJ = "b0111".U 30 | def InstrA = "b1110".U 31 | def InstrSA = "b1111".U // Atom Inst: SC 32 | 33 | def isrfWen(instrType : UInt): Bool = instrType(2) 34 | } 35 | 36 | // trait CompInstConst { 37 | // val RVCRegNumTable = Array( 38 | // BitPat("b000") -> 8.U, 39 | // BitPat("b001") -> 9.U, 40 | // BitPat("b010") -> 10.U, 41 | // BitPat("b011") -> 11.U, 42 | // BitPat("b100") -> 12.U, 43 | // BitPat("b101") -> 13.U, 44 | // BitPat("b110") -> 14.U, 45 | // BitPat("b111") -> 15.U 46 | // ) 47 | // } 48 | 49 | object SrcType { 50 | def reg = "b0".U 51 | def pc = "b1".U 52 | def imm = "b1".U 53 | def apply() = UInt(1.W) 54 | } 55 | 56 | object FuType extends HasNutCoreConst { 57 | def num = 5 58 | def alu = "b000".U 59 | def lsu = "b001".U 60 | def mdu = "b010".U 61 | def csr = "b011".U 62 | def mou = "b100".U 63 | def bru = if(IndependentBru) "b101".U 64 | else alu 65 | def apply() = UInt(log2Up(num).W) 66 | } 67 | 68 | object FuOpType { 69 | def apply() = UInt(7.W) 70 | } 71 | 72 | object Instructions extends HasInstrType with HasNutCoreParameter { 73 | def NOP = 0x00000013.U 74 | val DecodeDefault = List(InstrN, FuType.csr, CSROpType.jmp) 75 | def DecodeTable = RVIInstr.table ++ NutCoreTrap.table ++ 76 | (if (HasMExtension) RVMInstr.table else Array.empty) ++ 77 | (if (HasCExtension) RVCInstr.table else Array.empty) ++ 78 | Privileged.table ++ 79 | RVAInstr.table ++ 80 | RVZicsrInstr.table ++ RVZifenceiInstr.table 81 | } 82 | 83 | object CInstructions extends HasInstrType with HasNutCoreParameter{ 84 | def NOP = 0x00000013.U 85 | val DecodeDefault = List(RVCInstr.ImmNone, RVCInstr.DtCare, RVCInstr.DtCare, RVCInstr.DtCare) 86 | // val DecodeDefault = List(InstrN, FuType.csr, CSROpType.jmp) 87 | def CExtraDecodeTable = RVCInstr.cExtraTable 88 | } 89 | -------------------------------------------------------------------------------- /src/main/scala/nutcore/NutCoreTrap.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package nutcore 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | object NutCoreTrap extends HasInstrType { 23 | def StateGoodTrap = 0.U 24 | def StateBadTrap = 1.U 25 | def StateInvOpcode = 2.U 26 | def StateRunning = 3.U 27 | 28 | def TRAP = BitPat("b????????????_?????_000_?????_1101011") 29 | val table = Array(TRAP -> List(InstrI, FuType.alu, ALUOpType.add)) 30 | } 31 | 32 | class Monitor extends BlackBox { 33 | val io = IO(new Bundle { 34 | val clk = Input(Clock()) 35 | val reset = Input(Bool()) 36 | val isNutCoreTrap = Input(Bool()) 37 | val trapCode = Input(UInt(32.W)) 38 | val trapPC = Input(UInt(64.W)) 39 | val cycleCnt = Input(UInt(64.W)) 40 | val instrCnt = Input(UInt(64.W)) 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /src/main/scala/nutcore/RF.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package nutcore 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | import chisel3.util.experimental.BoringUtils 22 | 23 | import utils._ 24 | 25 | trait HasRegFileParameter { 26 | val NRReg = 32 27 | } 28 | 29 | class RegFile extends HasRegFileParameter with HasNutCoreParameter { 30 | val rf = Mem(NRReg, UInt(XLEN.W)) 31 | def read(addr: UInt) : UInt = Mux(addr === 0.U, 0.U, rf(addr)) 32 | def write(addr: UInt, data: UInt) = { rf(addr) := data(XLEN-1,0) } 33 | } 34 | 35 | class ScoreBoard extends HasRegFileParameter { 36 | val busy = RegInit(0.U(NRReg.W)) 37 | def isBusy(idx: UInt): Bool = busy(idx) 38 | def mask(idx: UInt) = (1.U(NRReg.W) << idx)(NRReg-1, 0) 39 | def update(setMask: UInt, clearMask: UInt) = { 40 | // When clearMask(i) and setMask(i) are both set, setMask(i) wins. 41 | // This can correctly record the busy bit when reg(i) is written 42 | // and issued at the same cycle. 43 | // Note that rf(0) is always free. 44 | busy := Cat(((busy & ~clearMask) | setMask)(NRReg-1, 1), 0.U(1.W)) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/scala/nutcore/backend/fu/MOU.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package nutcore 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | import chisel3.util.experimental.BoringUtils 22 | 23 | import utils._ 24 | 25 | // memory order unit 26 | object MOUOpType { 27 | def fence = "b00".U 28 | def fencei = "b01".U 29 | def sfence_vma = "b10".U 30 | } 31 | 32 | class MOUIO extends FunctionUnitIO { 33 | val cfIn = Flipped(new CtrlFlowIO) 34 | val redirect = new RedirectIO 35 | } 36 | 37 | class MOU extends NutCoreModule { 38 | val io = IO(new MOUIO) 39 | 40 | val (valid, src1, src2, func) = (io.in.valid, io.in.bits.src1, io.in.bits.src2, io.in.bits.func) 41 | def access(valid: Bool, src1: UInt, src2: UInt, func: UInt): UInt = { 42 | this.valid := valid 43 | this.src1 := src1 44 | this.src2 := src2 45 | this.func := func 46 | io.out.bits 47 | } 48 | 49 | io.redirect.target := io.cfIn.pc + 4.U 50 | io.redirect.valid := valid 51 | io.redirect.rtype := 0.U 52 | val flushICache = valid && (func === MOUOpType.fencei) 53 | BoringUtils.addSource(WireInit(flushICache), "MOUFlushICache") 54 | Debug(flushICache, "Flush I$ at %x\n", io.cfIn.pc) 55 | 56 | val flushTLB = valid && (func === MOUOpType.sfence_vma) 57 | BoringUtils.addSource(WireInit(flushTLB), "MOUFlushTLB") 58 | Debug(flushTLB, "Sfence.vma at %x\n", io.cfIn.pc) 59 | 60 | io.out.bits := 0.U 61 | io.in.ready := true.B 62 | io.out.valid := valid 63 | } 64 | -------------------------------------------------------------------------------- /src/main/scala/nutcore/backend/ooo/EP.scala: -------------------------------------------------------------------------------- 1 | package nutcore 2 | 3 | import chisel3._ 4 | import chisel3.util._ 5 | import chisel3.util.experimental.BoringUtils 6 | 7 | import utils._ 8 | 9 | // Out of Order Execution Pipeline for NutShell/Argo 10 | 11 | class ExecutionPipelineIO extends NutCoreBundle { 12 | val in = Flipped(Decoupled(new RenamedDecodeIO)) 13 | val out = Decoupled(new OOCommitIO) 14 | val mispredictRec = Input(new MisPredictionRecIO) 15 | val flush = Input(Bool()) 16 | } 17 | 18 | class ExecutionPipeline extends NutCoreModule { 19 | val io = IO(new ExecutionPipelineIO) 20 | def access(uop: Data): Data = { 21 | this.io.in := uop 22 | io.out 23 | } 24 | def updateBrMask(brMask: UInt) = { 25 | brMask & ~ (UIntToOH(io.mispredictRec.checkpoint) & Fill(checkpointSize, io.mispredictRec.valid)) 26 | } 27 | io.out.bits.isMMIO := false.B 28 | io.out.bits.intrNO := 0.U 29 | io.out.bits.exception := false.B 30 | io.out.bits.store := false.B 31 | } 32 | 33 | class ALUEP extends ExecutionPipeline { 34 | val alu = Module(new ALU()) 35 | alu.io.in.valid := io.in.valid 36 | alu.io.in.bits.src1 := io.in.bits.decode.data.src1 37 | alu.io.in.bits.src2 := io.in.bits.decode.data.src2 38 | alu.io.in.bits.func := io.in.bits.decode.ctrl.fuOpType 39 | alu.io.cfIn := io.in.bits.decode.cf 40 | alu.io.offset := io.in.bits.decode.data.imm 41 | alu.io.out.ready := io.out.ready 42 | 43 | io.out.bits.decode := io.in.bits.decode 44 | io.out.bits.decode.cf.redirect.valid := false.B 45 | io.out.bits.decode.cf.redirect.rtype := DontCare 46 | io.out.bits.commits := alu.io.out.bits 47 | io.out.bits.prfidx := io.in.bits.prfDest 48 | io.out.bits.brMask := io.in.bits.brMask 49 | 50 | io.in.ready := alu.io.in.ready 51 | io.out.valid := alu.io.out.valid 52 | } 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/main/scala/nutcore/backend/seq/ISU.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package nutcore 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | import chisel3.util.experimental.BoringUtils 22 | 23 | import utils._ 24 | import difftest._ 25 | 26 | // Sequential Inst Issue Unit 27 | class ISU(implicit val p: NutCoreConfig) extends NutCoreModule with HasRegFileParameter { 28 | val io = IO(new Bundle { 29 | val in = Vec(2, Flipped(Decoupled(new DecodeIO))) // make in-order backend compatible with high performance frontend 30 | val out = Decoupled(new DecodeIO) 31 | val wb = Flipped(new WriteBackIO) 32 | val forward = Flipped(new ForwardIO) 33 | val flush = Input(Bool()) 34 | }) 35 | 36 | io.out.bits := DontCare 37 | val rfSrc1 = io.in(0).bits.ctrl.rfSrc1 38 | val rfSrc2 = io.in(0).bits.ctrl.rfSrc2 39 | val rfDest1 = io.in(0).bits.ctrl.rfDest 40 | 41 | def isDepend(rfSrc: UInt, rfDest: UInt, wen: Bool): Bool = (rfSrc =/= 0.U) && (rfSrc === rfDest) && wen 42 | 43 | val forwardRfWen = io.forward.wb.rfWen && io.forward.valid 44 | val dontForward1 = (io.forward.fuType =/= FuType.alu) && (io.forward.fuType =/= FuType.lsu) 45 | val src1DependEX = isDepend(rfSrc1, io.forward.wb.rfDest, forwardRfWen) 46 | val src2DependEX = isDepend(rfSrc2, io.forward.wb.rfDest, forwardRfWen) 47 | val src1DependWB = isDepend(rfSrc1, io.wb.rfDest, io.wb.rfWen) 48 | val src2DependWB = isDepend(rfSrc2, io.wb.rfDest, io.wb.rfWen) 49 | 50 | val src1ForwardNextCycle = src1DependEX && !dontForward1 51 | val src2ForwardNextCycle = src2DependEX && !dontForward1 52 | val src1Forward = src1DependWB && Mux(dontForward1, !src1DependEX, true.B) 53 | val src2Forward = src2DependWB && Mux(dontForward1, !src2DependEX, true.B) 54 | 55 | val sb = new ScoreBoard 56 | val src1Ready = !sb.isBusy(rfSrc1) || src1ForwardNextCycle || src1Forward 57 | val src2Ready = !sb.isBusy(rfSrc2) || src2ForwardNextCycle || src2Forward 58 | io.out.valid := io.in(0).valid && src1Ready && src2Ready 59 | 60 | val rf = new RegFile 61 | 62 | // out1 63 | io.out.bits.data.src1 := Mux1H(List( 64 | (io.in(0).bits.ctrl.src1Type === SrcType.pc) -> SignExt(io.in(0).bits.cf.pc, AddrBits), 65 | src1ForwardNextCycle -> io.forward.wb.rfData, //io.forward.wb.rfData, 66 | (src1Forward && !src1ForwardNextCycle) -> io.wb.rfData, //io.wb.rfData, 67 | ((io.in(0).bits.ctrl.src1Type =/= SrcType.pc) && !src1ForwardNextCycle && !src1Forward) -> rf.read(rfSrc1) 68 | )) 69 | io.out.bits.data.src2 := Mux1H(List( 70 | (io.in(0).bits.ctrl.src2Type =/= SrcType.reg) -> io.in(0).bits.data.imm, 71 | src2ForwardNextCycle -> io.forward.wb.rfData, //io.forward.wb.rfData, 72 | (src2Forward && !src2ForwardNextCycle) -> io.wb.rfData, //io.wb.rfData, 73 | ((io.in(0).bits.ctrl.src2Type === SrcType.reg) && !src2ForwardNextCycle && !src2Forward) -> rf.read(rfSrc2) 74 | )) 75 | io.out.bits.data.imm := io.in(0).bits.data.imm 76 | 77 | io.out.bits.cf <> io.in(0).bits.cf 78 | io.out.bits.ctrl := io.in(0).bits.ctrl 79 | io.out.bits.ctrl.isSrc1Forward := src1ForwardNextCycle 80 | io.out.bits.ctrl.isSrc2Forward := src2ForwardNextCycle 81 | 82 | // retire: write rf 83 | when (io.wb.rfWen) { rf.write(io.wb.rfDest, io.wb.rfData) } 84 | 85 | val wbClearMask = Mux(io.wb.rfWen && !isDepend(io.wb.rfDest, io.forward.wb.rfDest, forwardRfWen), sb.mask(io.wb.rfDest), 0.U(NRReg.W)) 86 | // val isuFireSetMask = Mux(io.out.fire, sb.mask(rfDest), 0.U) 87 | val isuFireSetMask = Mux(io.out.fire, sb.mask(rfDest1), 0.U) 88 | when (io.flush) { sb.update(0.U, Fill(NRReg, 1.U(1.W))) } 89 | .otherwise { sb.update(isuFireSetMask, wbClearMask) } 90 | 91 | io.in(0).ready := !io.in(0).valid || io.out.fire 92 | io.in(1).ready := false.B 93 | 94 | Debug(io.out.fire, "issue: pc %x npc %x instr %x src1 %x src2 %x imm %x\n", io.out.bits.cf.pc, io.out.bits.cf.pnpc, io.out.bits.cf.instr, io.out.bits.data.src1, io.out.bits.data.src2, io.out.bits.data.imm) 95 | 96 | // read after write 97 | BoringUtils.addSource(WireInit(io.in(0).valid && !io.out.valid), "perfCntCondMrawStall") 98 | BoringUtils.addSource(WireInit(io.out.valid && !io.out.fire), "perfCntCondMexuBusy") 99 | BoringUtils.addSource(WireInit(io.out.fire), "perfCntCondISUIssue") 100 | 101 | if (!p.FPGAPlatform) { 102 | val difftest = DifftestModule(new DiffArchIntRegState) 103 | difftest.coreid := 0.U // TODO 104 | difftest.value := VecInit((0 to NRReg-1).map(i => rf.read(i.U))) 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/scala/nutcore/backend/seq/WBU.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package nutcore 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | import chisel3.util.experimental.BoringUtils 22 | import utils._ 23 | import difftest._ 24 | 25 | class WBU(implicit val p: NutCoreConfig) extends NutCoreModule{ 26 | val io = IO(new Bundle { 27 | val in = Flipped(Decoupled(new CommitIO)) 28 | val wb = new WriteBackIO 29 | val redirect = new RedirectIO 30 | }) 31 | 32 | io.wb.rfWen := io.in.bits.decode.ctrl.rfWen && io.in.valid 33 | io.wb.rfDest := io.in.bits.decode.ctrl.rfDest 34 | io.wb.rfData := io.in.bits.commits(io.in.bits.decode.ctrl.fuType) 35 | 36 | io.in.ready := true.B 37 | 38 | io.redirect := io.in.bits.decode.cf.redirect 39 | io.redirect.valid := io.in.bits.decode.cf.redirect.valid && io.in.valid 40 | 41 | Debug(io.in.valid, "[COMMIT] pc = 0x%x inst %x wen %x wdst %x wdata %x mmio %x intrNO %x\n", io.in.bits.decode.cf.pc, io.in.bits.decode.cf.instr, io.wb.rfWen, io.wb.rfDest, io.wb.rfData, io.in.bits.isMMIO, io.in.bits.intrNO) 42 | 43 | val falseWire = WireInit(false.B) // make BoringUtils.addSource happy 44 | BoringUtils.addSource(io.in.valid, "perfCntCondMinstret") 45 | BoringUtils.addSource(falseWire, "perfCntCondMultiCommit") 46 | 47 | if (!p.FPGAPlatform) { 48 | val difftest_commit = DifftestModule(new DiffInstrCommit, delay = 1, dontCare = true) 49 | difftest_commit.coreid := 0.U 50 | difftest_commit.index := 0.U 51 | difftest_commit.valid := io.in.valid 52 | difftest_commit.pc := SignExt(io.in.bits.decode.cf.pc, AddrBits) 53 | difftest_commit.instr := io.in.bits.decode.cf.instr 54 | difftest_commit.skip := io.in.bits.isMMIO 55 | difftest_commit.isRVC := io.in.bits.decode.cf.instr(1,0)=/="b11".U 56 | difftest_commit.rfwen := io.wb.rfWen && io.wb.rfDest =/= 0.U // && valid(ringBufferTail)(i) && commited(ringBufferTail)(i) 57 | difftest_commit.fpwen := false.B 58 | difftest_commit.wdest := io.wb.rfDest 59 | difftest_commit.wpdest := io.wb.rfDest 60 | 61 | val difftest_wb = DifftestModule(new DiffIntWriteback, delay = 1) 62 | difftest_wb.coreid := 0.U 63 | difftest_wb.valid := io.wb.rfWen && io.wb.rfDest =/= 0.U 64 | difftest_wb.address := io.wb.rfDest 65 | difftest_wb.data := io.wb.rfData 66 | } else { 67 | BoringUtils.addSource(io.in.valid, "ilaWBUvalid") 68 | BoringUtils.addSource(io.in.bits.decode.cf.pc, "ilaWBUpc") 69 | BoringUtils.addSource(io.wb.rfWen, "ilaWBUrfWen") 70 | BoringUtils.addSource(io.wb.rfDest, "ilaWBUrfDest") 71 | BoringUtils.addSource(io.wb.rfData, "ilaWBUrfData") 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/scala/nutcore/frontend/Frontend.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package nutcore 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | import utils._ 22 | import bus.simplebus._ 23 | 24 | class FrontendIO(implicit val p: NutCoreConfig) extends Bundle with HasNutCoreConst { 25 | val imem = new SimpleBusUC(userBits = ICacheUserBundleWidth, addrBits = VAddrBits) 26 | val out = Vec(2, Decoupled(new DecodeIO)) 27 | val flushVec = Output(UInt(4.W)) 28 | val redirect = Flipped(new RedirectIO) 29 | val bpFlush = Output(Bool()) 30 | val ipf = Input(Bool()) 31 | } 32 | 33 | 34 | trait HasFrontendIO { 35 | implicit val p: NutCoreConfig 36 | val io = IO(new FrontendIO) 37 | } 38 | 39 | class Frontend_ooo(implicit val p: NutCoreConfig) extends NutCoreModule with HasFrontendIO { 40 | def pipelineConnect2[T <: Data](left: DecoupledIO[T], right: DecoupledIO[T], 41 | isFlush: Bool, entries: Int = 4, pipe: Boolean = false) = { 42 | // NOTE: depend on https://github.com/chipsalliance/chisel3/pull/2245 43 | // right <> Queue(left, entries = entries, pipe = pipe, flush = Some(isFlush)) 44 | right <> FlushableQueue(left, isFlush, entries = entries, pipe = pipe) 45 | } 46 | 47 | val ifu = Module(new IFU_ooo) 48 | val ibf = Module(new IBF) 49 | val idu = Module(new IDU) 50 | 51 | pipelineConnect2(ifu.io.out, ibf.io.in, ifu.io.flushVec(0)) 52 | PipelineVector2Connect(new CtrlFlowIO, ibf.io.out(0), ibf.io.out(1), idu.io.in(0), idu.io.in(1), ifu.io.flushVec(1), if (EnableOutOfOrderExec) 8 else 4) 53 | ibf.io.flush := ifu.io.flushVec(1) 54 | 55 | io.out <> idu.io.out 56 | io.redirect <> ifu.io.redirect 57 | io.flushVec <> ifu.io.flushVec 58 | io.bpFlush <> ifu.io.bpFlush 59 | io.ipf <> ifu.io.ipf 60 | io.imem <> ifu.io.imem 61 | 62 | Debug("------------------------ FRONTEND:------------------------\n") 63 | Debug("flush = %b, ifu:(%d,%d), ibf:(%d,%d), idu:(%d,%d)\n", 64 | ifu.io.flushVec.asUInt, ifu.io.out.valid, ifu.io.out.ready, 65 | ibf.io.in.valid, ibf.io.in.ready, idu.io.in(0).valid, idu.io.in(0).ready) 66 | Debug(ifu.io.out.valid, "IFU: pc = 0x%x, instr = 0x%x\n", ifu.io.out.bits.pc, ifu.io.out.bits.instr) 67 | Debug(ibf.io.in.valid, "IBF: pc = 0x%x, instr = 0x%x\n", ibf.io.in.bits.pc, ibf.io.in.bits.instr) 68 | Debug(idu.io.in(0).valid, "IDU1: pc = 0x%x, instr = 0x%x, pnpc = 0x%x\n", idu.io.in(0).bits.pc, idu.io.in(0).bits.instr, idu.io.in(0).bits.pnpc) 69 | Debug(idu.io.in(1).valid, "IDU2: pc = 0x%x, instr = 0x%x, pnpc = 0x%x\n", idu.io.in(1).bits.pc, idu.io.in(1).bits.instr, idu.io.in(1).bits.pnpc) 70 | } 71 | 72 | class Frontend_embedded(implicit val p: NutCoreConfig) extends NutCoreModule with HasFrontendIO { 73 | val ifu = Module(new IFU_embedded) 74 | val idu = Module(new IDU) 75 | 76 | PipelineConnect(ifu.io.out, idu.io.in(0), idu.io.out(0).fire, ifu.io.flushVec(0)) 77 | idu.io.in(1) := DontCare 78 | 79 | io.out <> idu.io.out 80 | io.redirect <> ifu.io.redirect 81 | io.flushVec <> ifu.io.flushVec 82 | io.bpFlush <> ifu.io.bpFlush 83 | io.ipf <> ifu.io.ipf 84 | io.imem <> ifu.io.imem 85 | 86 | Debug("------------------------ FRONTEND:------------------------\n") 87 | Debug("flush = %b, ifu:(%d,%d), idu:(%d,%d)\n", 88 | ifu.io.flushVec.asUInt, ifu.io.out.valid, ifu.io.out.ready, idu.io.in(0).valid, idu.io.in(0).ready) 89 | Debug(ifu.io.out.valid, "IFU: pc = 0x%x, instr = 0x%x\n", ifu.io.out.bits.pc, ifu.io.out.bits.instr) 90 | Debug(idu.io.in(0).valid, "IDU1: pc = 0x%x, instr = 0x%x, pnpc = 0x%x\n", idu.io.in(0).bits.pc, idu.io.in(0).bits.instr, idu.io.in(0).bits.pnpc) 91 | } 92 | 93 | class Frontend_inorder(implicit val p: NutCoreConfig) extends NutCoreModule with HasFrontendIO { 94 | val ifu = Module(new IFU_inorder) 95 | val ibf = Module(new NaiveRVCAlignBuffer) 96 | val idu = Module(new IDU) 97 | 98 | def PipelineConnect2[T <: Data](left: DecoupledIO[T], right: DecoupledIO[T], 99 | isFlush: Bool, entries: Int = 4, pipe: Boolean = false) = { 100 | // NOTE: depend on https://github.com/chipsalliance/chisel3/pull/2245 101 | // right <> Queue(left, entries = entries, pipe = pipe, flush = Some(isFlush)) 102 | right <> FlushableQueue(left, isFlush, entries = entries, pipe = pipe) 103 | } 104 | 105 | PipelineConnect2(ifu.io.out, ibf.io.in, ifu.io.flushVec(0)) 106 | PipelineConnect(ibf.io.out, idu.io.in(0), idu.io.out(0).fire, ifu.io.flushVec(1)) 107 | idu.io.in(1) := DontCare 108 | 109 | ibf.io.flush := ifu.io.flushVec(1) 110 | io.out <> idu.io.out 111 | io.redirect <> ifu.io.redirect 112 | io.flushVec <> ifu.io.flushVec 113 | io.bpFlush <> ifu.io.bpFlush 114 | io.ipf <> ifu.io.ipf 115 | io.imem <> ifu.io.imem 116 | 117 | Debug("------------------------ FRONTEND:------------------------\n") 118 | Debug("flush = %b, ifu:(%d,%d), idu:(%d,%d)\n", 119 | ifu.io.flushVec.asUInt, ifu.io.out.valid, ifu.io.out.ready, idu.io.in(0).valid, idu.io.in(0).ready) 120 | Debug(ifu.io.out.valid, "IFU: pc = 0x%x, instr = 0x%x\n", ifu.io.out.bits.pc, ifu.io.out.bits.instr) 121 | Debug(idu.io.in(0).valid, "IDU1: pc = 0x%x, instr = 0x%x, pnpc = 0x%x\n", idu.io.in(0).bits.pc, idu.io.in(0).bits.instr, idu.io.in(0).bits.pnpc) 122 | } -------------------------------------------------------------------------------- /src/main/scala/nutcore/isa/Privileged.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package nutcore 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | import top.Settings 23 | 24 | object Privileged extends HasInstrType { 25 | def ECALL = BitPat("b000000000000_00000_000_00000_1110011") 26 | def EBREAK = BitPat("b000000000001_00000_000_00000_1110011") 27 | def MRET = BitPat("b001100000010_00000_000_00000_1110011") 28 | def SRET = BitPat("b000100000010_00000_000_00000_1110011") 29 | def SFANCE_VMA = BitPat("b0001001_?????_?????_000_00000_1110011") 30 | def FENCE = BitPat("b????????????_?????_000_?????_0001111") 31 | def WFI = BitPat("b0001000_00101_00000_000_00000_1110011") 32 | 33 | val table_s = Array( 34 | SRET -> List(InstrI, FuType.csr, CSROpType.jmp), 35 | SFANCE_VMA -> List(InstrR, FuType.mou, MOUOpType.sfence_vma) 36 | ) 37 | 38 | val table = Array( 39 | ECALL -> List(InstrI, FuType.csr, CSROpType.jmp), 40 | EBREAK -> List(InstrI, FuType.csr, CSROpType.jmp), 41 | MRET -> List(InstrI, FuType.csr, CSROpType.jmp), 42 | FENCE -> List(InstrS, FuType.mou, MOUOpType.fence), // nop InstrS -> !wen 43 | WFI -> List(InstrI, FuType.alu, ALUOpType.add) // nop 44 | // FENCE -> List(InstrB, FuType.mou, MOUOpType.fencei) 45 | ) ++ (if (!Settings.get("MmodeOnly")) table_s else Array.empty) 46 | } 47 | -------------------------------------------------------------------------------- /src/main/scala/nutcore/isa/RVA.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package nutcore 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | object RVAInstr extends HasInstrType { 23 | // Note: use instr(14,12) to distinguish D/W inst 24 | // def LR = BitPat("b00010??00000_?????_???_?????_0101111") 25 | // def SC = BitPat("b00011??00000_?????_???_?????_0101111") 26 | def LR_D = BitPat("b00010_??_00000_?????_011_?????_0101111") 27 | def SC_D = BitPat("b00011_??_?????_?????_011_?????_0101111") 28 | def LR_W = BitPat("b00010_??_00000_?????_010_?????_0101111") 29 | def SC_W = BitPat("b00011_??_?????_?????_010_?????_0101111") 30 | def AMOSWAP = BitPat("b00001_??_?????_?????_01?_?????_0101111") 31 | def AMOADD = BitPat("b00000_??_?????_?????_01?_?????_0101111") 32 | def AMOXOR = BitPat("b00100_??_?????_?????_01?_?????_0101111") 33 | def AMOAND = BitPat("b01100_??_?????_?????_01?_?????_0101111") 34 | def AMOOR = BitPat("b01000_??_?????_?????_01?_?????_0101111") 35 | def AMOMIN = BitPat("b10000_??_?????_?????_01?_?????_0101111") 36 | def AMOMAX = BitPat("b10100_??_?????_?????_01?_?????_0101111") 37 | def AMOMINU = BitPat("b11000_??_?????_?????_01?_?????_0101111") 38 | def AMOMAXU = BitPat("b11100_??_?????_?????_01?_?????_0101111") 39 | // funct3 === 010 or 011 40 | 41 | val table = Array( 42 | // LR -> List(InstrI, FuType.lsu, LSUOpType.lr), 43 | LR_D -> List(InstrI, FuType.lsu, LSUOpType.lr), 44 | LR_W -> List(InstrI, FuType.lsu, LSUOpType.lr), 45 | // SC -> List(InstrS, FuType.lsu, LSUOpType.sc), 46 | SC_D -> List(InstrSA, FuType.lsu, LSUOpType.sc), 47 | SC_W -> List(InstrSA, FuType.lsu, LSUOpType.sc), 48 | AMOSWAP -> List(InstrR, FuType.lsu, LSUOpType.amoswap), 49 | AMOADD -> List(InstrR, FuType.lsu, LSUOpType.amoadd), 50 | AMOXOR -> List(InstrR, FuType.lsu, LSUOpType.amoxor), 51 | AMOAND -> List(InstrR, FuType.lsu, LSUOpType.amoand), 52 | AMOOR -> List(InstrR, FuType.lsu, LSUOpType.amoor), 53 | AMOMIN -> List(InstrR, FuType.lsu, LSUOpType.amomin), 54 | AMOMAX -> List(InstrR, FuType.lsu, LSUOpType.amomax), 55 | AMOMINU -> List(InstrR, FuType.lsu, LSUOpType.amominu), 56 | AMOMAXU -> List(InstrR, FuType.lsu, LSUOpType.amomaxu) 57 | ) 58 | } 59 | -------------------------------------------------------------------------------- /src/main/scala/nutcore/isa/RVM.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package nutcore 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | object RV32MInstr extends HasInstrType with HasNutCoreParameter { 23 | def MUL = BitPat("b0000001_?????_?????_000_?????_0110011") 24 | def MULH = BitPat("b0000001_?????_?????_001_?????_0110011") 25 | def MULHSU = BitPat("b0000001_?????_?????_010_?????_0110011") 26 | def MULHU = BitPat("b0000001_?????_?????_011_?????_0110011") 27 | def DIV = BitPat("b0000001_?????_?????_100_?????_0110011") 28 | def DIVU = BitPat("b0000001_?????_?????_101_?????_0110011") 29 | def REM = BitPat("b0000001_?????_?????_110_?????_0110011") 30 | def REMU = BitPat("b0000001_?????_?????_111_?????_0110011") 31 | def MULW = BitPat("b0000001_?????_?????_000_?????_0111011") 32 | def DIVW = BitPat("b0000001_?????_?????_100_?????_0111011") 33 | def DIVUW = BitPat("b0000001_?????_?????_101_?????_0111011") 34 | def REMW = BitPat("b0000001_?????_?????_110_?????_0111011") 35 | def REMUW = BitPat("b0000001_?????_?????_111_?????_0111011") 36 | 37 | val mulTable = Array( 38 | MUL -> List(InstrR, FuType.mdu, MDUOpType.mul), 39 | MULH -> List(InstrR, FuType.mdu, MDUOpType.mulh), 40 | MULHSU -> List(InstrR, FuType.mdu, MDUOpType.mulhsu), 41 | MULHU -> List(InstrR, FuType.mdu, MDUOpType.mulhu) 42 | ) 43 | val divTable = Array( 44 | DIV -> List(InstrR, FuType.mdu, MDUOpType.div), 45 | DIVU -> List(InstrR, FuType.mdu, MDUOpType.divu), 46 | REM -> List(InstrR, FuType.mdu, MDUOpType.rem), 47 | REMU -> List(InstrR, FuType.mdu, MDUOpType.remu) 48 | ) 49 | val table = mulTable ++ (if (HasDiv) divTable else Array.empty) 50 | } 51 | 52 | object RV64MInstr extends HasInstrType with HasNutCoreParameter { 53 | def MULW = BitPat("b0000001_?????_?????_000_?????_0111011") 54 | def DIVW = BitPat("b0000001_?????_?????_100_?????_0111011") 55 | def DIVUW = BitPat("b0000001_?????_?????_101_?????_0111011") 56 | def REMW = BitPat("b0000001_?????_?????_110_?????_0111011") 57 | def REMUW = BitPat("b0000001_?????_?????_111_?????_0111011") 58 | 59 | val mulTable = Array( 60 | MULW -> List(InstrR, FuType.mdu, MDUOpType.mulw) 61 | ) 62 | val divTable = Array( 63 | DIVW -> List(InstrR, FuType.mdu, MDUOpType.divw), 64 | DIVUW -> List(InstrR, FuType.mdu, MDUOpType.divuw), 65 | REMW -> List(InstrR, FuType.mdu, MDUOpType.remw), 66 | REMUW -> List(InstrR, FuType.mdu, MDUOpType.remuw) 67 | ) 68 | val table = mulTable ++ (if (HasDiv) divTable else Array.empty) 69 | } 70 | 71 | object RVMInstr extends HasNutCoreParameter { 72 | val table = RV32MInstr.table ++ (if (XLEN == 64) RV64MInstr.table else Array.empty) 73 | } 74 | -------------------------------------------------------------------------------- /src/main/scala/nutcore/isa/RVZicsr.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package nutcore 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | object RVZicsrInstr extends HasInstrType { 23 | def CSRRW = BitPat("b????????????_?????_001_?????_1110011") 24 | def CSRRS = BitPat("b????????????_?????_010_?????_1110011") 25 | def CSRRC = BitPat("b????????????_?????_011_?????_1110011") 26 | def CSRRWI = BitPat("b????????????_?????_101_?????_1110011") 27 | def CSRRSI = BitPat("b????????????_?????_110_?????_1110011") 28 | def CSRRCI = BitPat("b????????????_?????_111_?????_1110011") 29 | 30 | val table = Array( 31 | CSRRW -> List(InstrI, FuType.csr, CSROpType.wrt), 32 | CSRRS -> List(InstrI, FuType.csr, CSROpType.set), 33 | CSRRC -> List(InstrI, FuType.csr, CSROpType.clr), 34 | CSRRWI -> List(InstrI, FuType.csr, CSROpType.wrti), 35 | CSRRSI -> List(InstrI, FuType.csr, CSROpType.seti), 36 | CSRRCI -> List(InstrI, FuType.csr, CSROpType.clri) 37 | ) 38 | } 39 | -------------------------------------------------------------------------------- /src/main/scala/nutcore/isa/RVZifencei.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package nutcore 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | object RVZifenceiInstr extends HasInstrType { 23 | def FENCEI = BitPat("b000000000000_00000_001_00000_0001111") 24 | 25 | val table = Array( 26 | FENCEI -> List(InstrB, FuType.mou, MOUOpType.fencei) 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /src/main/scala/nutcore/isa/predecode/predecode.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package nutcore 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | object PreDecode { 23 | def C_JAL = BitPat("b001_?_??_???_??_???_01") 24 | def C_J = BitPat("b101_?_??_???_??_???_01") 25 | def C_BEQZ = BitPat("b110_?_??_???_??_???_01") 26 | def C_BNEZ = BitPat("b111_?_??_???_??_???_01") 27 | def RVI_BRANCH = BitPat("b???_?_??_???_11_???_11") 28 | 29 | val branchTable = Array( 30 | C_JAL -> List(true.B), 31 | C_J -> List(true.B), 32 | C_BEQZ -> List(true.B), 33 | C_BNEZ -> List(true.B), 34 | RVI_BRANCH -> List(true.B) 35 | ) 36 | } -------------------------------------------------------------------------------- /src/main/scala/nutcore/utils/WritebackDelayer.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package nutcore 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | import utils._ 23 | 24 | class WritebackDelayer(bru: Boolean = false, name: String = "unnamedDelayer") extends NutCoreModule with HasRSConst with HasBackendConst { 25 | val io = IO(new Bundle { 26 | val in = Flipped(Decoupled(new OOCommitIO)) 27 | val out = Decoupled(new OOCommitIO) 28 | val mispredictRec = Flipped(new MisPredictionRecIO) 29 | val flush = Input(Bool()) 30 | val checkpointIn = if (bru) Some(Input(UInt(brTagWidth.W))) else None 31 | val freeCheckpoint = if (bru) Some(Output(Valid(UInt(brTagWidth.W)))) else None 32 | }) 33 | 34 | val valid = RegInit(false.B) 35 | val brMask = Reg(UInt(checkpointSize.W)) 36 | 37 | def needMispredictionRecovery(brMask: UInt) = { 38 | io.mispredictRec.valid && io.mispredictRec.redirect.valid && brMask(io.mispredictRec.checkpoint) 39 | } 40 | 41 | def updateBrMask(brMask: UInt) = { 42 | brMask & ~ (UIntToOH(io.mispredictRec.checkpoint) & Fill(checkpointSize, io.mispredictRec.valid)) 43 | } 44 | 45 | brMask := updateBrMask(brMask) 46 | when(io.in.fire){brMask := updateBrMask(io.in.bits.brMask)} 47 | when(needMispredictionRecovery(brMask) || io.out.fire){valid := false.B} 48 | when(io.in.fire){valid := true.B} 49 | when(io.flush) {valid := false.B} 50 | 51 | io.in.ready := (!valid || io.out.fire) && !needMispredictionRecovery(io.in.bits.brMask) 52 | io.out.bits <> RegEnable(io.in.bits, io.in.fire) 53 | io.out.bits.brMask := brMask 54 | io.out.valid := valid 55 | 56 | if(bru){ 57 | io.freeCheckpoint.get.bits <> RegEnable(io.checkpointIn.get, io.in.fire) 58 | io.freeCheckpoint.get.valid := io.out.fire 59 | } 60 | 61 | Debug(valid, "[WBDelay-"+name+"] delayer valid: pc %x brMask %x\n", io.out.bits.decode.cf.pc, brMask) 62 | } 63 | 64 | 65 | object WritebackDelayer { 66 | def apply(in: Data, mispredictRec: Data, flush: Bool) = { 67 | val delayer = Module(new WritebackDelayer()) 68 | delayer.io.in := in 69 | delayer.io.mispredictRec := mispredictRec 70 | delayer.io.flush := flush 71 | delayer 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/scala/sim/MeipGen.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package sim 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | import device._ 23 | import bus.axi4._ 24 | import utils._ 25 | 26 | class MeipGenIO extends Bundle { 27 | val meip = Output(Bool()) 28 | } 29 | 30 | class AXI4MeipGen extends AXI4SlaveModule(new AXI4Lite, new MeipGenIO) { 31 | val meip = RegInit(false.B) 32 | 33 | val mapping = Map( 34 | RegMap(0x0, meip) 35 | ) 36 | 37 | def getOffset(addr: UInt) = addr(3, 0) 38 | RegMap.generate(mapping, getOffset(raddr), in.r.bits.data, 39 | getOffset(waddr), in.w.fire, in.w.bits.data(0), MaskExpand(in.w.bits.strb)(0)) 40 | 41 | io.extra.get.meip := meip 42 | } 43 | -------------------------------------------------------------------------------- /src/main/scala/sim/NutShellSim.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package sim 18 | 19 | import bus.axi4._ 20 | import chisel3._ 21 | import device.AXI4RAM 22 | import difftest._ 23 | import nutcore.NutCoreConfig 24 | import system._ 25 | 26 | class SimTop extends Module { 27 | lazy val config = NutCoreConfig(FPGAPlatform = false) 28 | val soc = Module(new NutShell()(config)) 29 | val mem = Module(new AXI4RAM(memByte = 2L * 1024 * 1024 * 1024, useBlackBox = true)) 30 | // Be careful with the commit checking of emu. 31 | // A large delay will make emu incorrectly report getting stuck. 32 | val memdelay = Module(new AXI4Delayer(0)) 33 | val mmio = Module(new SimMMIO) 34 | 35 | soc.io.frontend <> mmio.io.dma 36 | 37 | memdelay.io.in <> soc.io.mem 38 | mem.io.in <> memdelay.io.out 39 | 40 | mmio.io.rw <> soc.io.mmio 41 | 42 | soc.io.meip := mmio.io.meip 43 | 44 | val difftest = DifftestModule.finish("nutshell") 45 | difftest.uart <> mmio.io.uart 46 | } 47 | -------------------------------------------------------------------------------- /src/main/scala/sim/SimMMIO.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package sim 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | import bus.simplebus._ 23 | import bus.axi4._ 24 | import device._ 25 | import difftest._ 26 | 27 | class SimMMIO extends Module { 28 | val io = IO(new Bundle { 29 | val rw = Flipped(new SimpleBusUC) 30 | val meip = Output(Bool()) 31 | val dma = new AXI4 32 | val uart = new UARTIO 33 | }) 34 | 35 | val devAddrSpace = List( 36 | (0x40600000L, 0x10L), // uart 37 | (0x50000000L, 0x400000L), // vmem 38 | (0x40001000L, 0x8L), // vga ctrl 39 | (0x40000000L, 0x1000L), // flash 40 | (0x40002000L, 0x1000L), // dummy sdcard 41 | (0x40004000L, 0x1000L), // meipGen 42 | (0x40003000L, 0x1000L) // dma 43 | ) 44 | 45 | val xbar = Module(new SimpleBusCrossbar1toN(devAddrSpace)) 46 | xbar.io.in <> io.rw 47 | 48 | val uart = Module(new AXI4UART) 49 | val vga = Module(new AXI4VGA(sim = true)) 50 | val flash = Module(new AXI4Flash) 51 | val sd = Module(new AXI4DummySD) 52 | val meipGen = Module(new AXI4MeipGen) 53 | val dma = Module(new AXI4DMA) 54 | uart.io.in <> xbar.io.out(0).toAXI4Lite 55 | vga.io.in.fb <> xbar.io.out(1).toAXI4Lite 56 | vga.io.in.ctrl <> xbar.io.out(2).toAXI4Lite 57 | flash.io.in <> xbar.io.out(3).toAXI4Lite 58 | sd.io.in <> xbar.io.out(4).toAXI4Lite 59 | meipGen.io.in <> xbar.io.out(5).toAXI4Lite 60 | dma.io.in <> xbar.io.out(6).toAXI4Lite 61 | io.dma <> dma.io.extra.get.dma 62 | io.meip := meipGen.io.extra.get.meip 63 | uart.io.extra.get <> io.uart 64 | vga.io.vga := DontCare 65 | } 66 | -------------------------------------------------------------------------------- /src/main/scala/system/Coherence.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package system 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | import utils._ 23 | import bus.simplebus._ 24 | import nutcore.HasNutCoreParameter 25 | 26 | trait HasCoherenceParameter extends HasNutCoreParameter { 27 | val supportCoh = HasDcache 28 | } 29 | 30 | class CoherenceManager extends Module with HasCoherenceParameter { 31 | val io = IO(new Bundle { 32 | val in = Flipped(new SimpleBusUC) 33 | val out = new Bundle { 34 | val mem = new SimpleBusUC 35 | val coh = new SimpleBusUC 36 | } 37 | }) 38 | 39 | // state transition: 40 | // write: s_idle -> s_memWriteResp -> s_idle 41 | // read: s_idle -> s_probeResp -> (hit) s_probeForward -> s_idle 42 | // +> (miss) s_memReadReq -> s_memReadResp -> s_idle 43 | 44 | val s_idle :: s_probeResp :: s_probeForward :: s_memReadReq :: s_memReadResp :: s_memWriteResp :: Nil = Enum(6) 45 | val state = RegInit(s_idle) 46 | val inflight = state =/= s_idle 47 | 48 | val thisReq = io.in.req 49 | assert(!(thisReq.valid && !thisReq.bits.isRead() && !thisReq.bits.isWrite())) 50 | 51 | // when read, we should first probe dcache 52 | val reqLatch = RegEnable(thisReq.bits, !inflight && thisReq.bits.isRead()) 53 | io.out.coh match { case c => { 54 | c.req.bits := thisReq.bits 55 | c.req.bits.cmd := SimpleBusCmd.probe 56 | c.resp.ready := true.B 57 | }} 58 | 59 | io.out.mem.req.bits := thisReq.bits 60 | // bind correct valid and ready signals 61 | io.out.mem.req.valid := false.B 62 | thisReq.ready := false.B 63 | io.out.coh.req.valid := false.B 64 | when (if (supportCoh) thisReq.bits.isWrite() else true.B) { 65 | io.out.mem.req.valid := thisReq.valid && !inflight 66 | thisReq.ready := io.out.mem.req.ready && !inflight 67 | } .elsewhen (thisReq.bits.isRead()) { 68 | io.out.coh.req.valid := thisReq.valid && !inflight 69 | thisReq.ready := io.out.coh.req.ready && !inflight 70 | } 71 | 72 | io.in.resp <> io.out.mem.resp 73 | 74 | switch (state) { 75 | is (s_idle) { 76 | when (thisReq.fire) { 77 | when (thisReq.bits.isRead()) { state := Mux(supportCoh.B, s_probeResp, s_memReadResp) } 78 | .elsewhen (thisReq.bits.isWriteLast()) { state := s_memWriteResp } 79 | } 80 | } 81 | is (s_probeResp) { 82 | when (io.out.coh.resp.fire) { 83 | state := Mux(io.out.coh.resp.bits.isProbeHit, s_probeForward, s_memReadReq) 84 | } 85 | } 86 | is (s_probeForward) { 87 | val thisResp = io.in.resp 88 | thisResp <> io.out.coh.resp 89 | when (thisResp.fire && thisResp.bits.isReadLast) { state := s_idle } 90 | } 91 | is (s_memReadReq) { 92 | io.out.mem.req.bits := reqLatch 93 | io.out.mem.req.valid := true.B 94 | when (io.out.mem.req.fire) { state := s_memReadResp } 95 | } 96 | is (s_memReadResp) { when (io.out.mem.resp.fire && io.out.mem.resp.bits.isReadLast) { state := s_idle } } 97 | is (s_memWriteResp) { when (io.out.mem.resp.fire) { state := s_idle } } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/scala/system/NutShell.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package system 18 | 19 | import nutcore._ 20 | import bus.axi4.{AXI4, AXI4Lite} 21 | import bus.simplebus._ 22 | import device.{AXI4CLINT, AXI4PLIC} 23 | import top.Settings 24 | 25 | import chisel3._ 26 | import chisel3.util._ 27 | import chisel3.util.experimental.BoringUtils 28 | 29 | trait HasSoCParameter { 30 | val EnableILA = Settings.get("EnableILA") 31 | val HasL2cache = Settings.get("HasL2cache") 32 | val HasPrefetch = Settings.get("HasPrefetch") 33 | } 34 | 35 | class ILABundle extends NutCoreBundle { 36 | val WBUpc = UInt(VAddrBits.W) 37 | val WBUvalid = UInt(1.W) 38 | val WBUrfWen = UInt(1.W) 39 | val WBUrfDest = UInt(5.W) 40 | val WBUrfData = UInt(XLEN.W) 41 | val InstrCnt = UInt(64.W) 42 | } 43 | 44 | class NutShell(implicit val p: NutCoreConfig) extends Module with HasSoCParameter { 45 | val io = IO(new Bundle{ 46 | val mem = new AXI4 47 | val mmio = (if (p.FPGAPlatform) { new AXI4 } else { new SimpleBusUC }) 48 | val frontend = Flipped(new AXI4) 49 | val meip = Input(UInt(Settings.getInt("NrExtIntr").W)) 50 | val ila = if (p.FPGAPlatform && EnableILA) Some(Output(new ILABundle)) else None 51 | }) 52 | 53 | val nutcore = Module(new NutCore) 54 | val cohMg = Module(new CoherenceManager) 55 | val xbar = Module(new SimpleBusCrossbarNto1(2)) 56 | cohMg.io.in <> nutcore.io.imem.mem 57 | nutcore.io.dmem.coh <> cohMg.io.out.coh 58 | xbar.io.in(0) <> cohMg.io.out.mem 59 | xbar.io.in(1) <> nutcore.io.dmem.mem 60 | 61 | val axi2sb = Module(new AXI42SimpleBusConverter()) 62 | axi2sb.io.in <> io.frontend 63 | nutcore.io.frontend <> axi2sb.io.out 64 | 65 | val memport = xbar.io.out.toMemPort 66 | memport.resp.bits.data := DontCare 67 | memport.resp.valid := DontCare 68 | memport.req.ready := DontCare 69 | 70 | val mem = if (HasL2cache) { 71 | val l2cacheOut = Wire(new SimpleBusC) 72 | val l2cacheIn = if (HasPrefetch) { 73 | val prefetcher = Module(new Prefetcher) 74 | val l2cacheIn = Wire(new SimpleBusUC) 75 | prefetcher.io.in <> xbar.io.out.req 76 | l2cacheIn.req <> prefetcher.io.out 77 | xbar.io.out.resp <> l2cacheIn.resp 78 | l2cacheIn 79 | } else xbar.io.out 80 | val l2Empty = Wire(Bool()) 81 | l2cacheOut <> Cache(in = l2cacheIn, mmio = 0.U.asTypeOf(new SimpleBusUC) :: Nil, flush = "b00".U, empty = l2Empty, enable = true)( 82 | CacheConfig(name = "l2cache", totalSize = 128, cacheLevel = 2)) 83 | l2cacheOut.coh.resp.ready := true.B 84 | l2cacheOut.coh.req.valid := false.B 85 | l2cacheOut.coh.req.bits := DontCare 86 | l2cacheOut.mem 87 | } else { 88 | xbar.io.out 89 | } 90 | 91 | val memMapRegionBits = Settings.getInt("MemMapRegionBits") 92 | val memMapBase = Settings.getLong("MemMapBase") 93 | val memAddrMap = Module(new SimpleBusAddressMapper((memMapRegionBits, memMapBase))) 94 | memAddrMap.io.in <> mem 95 | io.mem <> memAddrMap.io.out.toAXI4(true) 96 | 97 | nutcore.io.imem.coh.resp.ready := true.B 98 | nutcore.io.imem.coh.req.valid := false.B 99 | nutcore.io.imem.coh.req.bits := DontCare 100 | 101 | val addrSpace = List( 102 | (0x38000000L, 0x00010000L), // CLINT 103 | (0x3c000000L, 0x04000000L), // PLIC 104 | (Settings.getLong("MMIOBase"), Settings.getLong("MMIOSize")), // external devices 105 | ) 106 | val mmioXbar = Module(new SimpleBusCrossbar1toN(addrSpace)) 107 | mmioXbar.io.in <> nutcore.io.mmio 108 | 109 | val extDev = mmioXbar.io.out(2) 110 | if (p.FPGAPlatform) { io.mmio <> extDev.toAXI4() } 111 | else { io.mmio <> extDev } 112 | 113 | val clint = Module(new AXI4CLINT(sim = !p.FPGAPlatform)) 114 | clint.io.in <> mmioXbar.io.out(0).toAXI4Lite 115 | val mtipSync = clint.io.extra.get.mtip 116 | val msipSync = clint.io.extra.get.msip 117 | BoringUtils.addSource(mtipSync, "mtip") 118 | BoringUtils.addSource(msipSync, "msip") 119 | 120 | val plic = Module(new AXI4PLIC(nrIntr = Settings.getInt("NrExtIntr"), nrHart = 1)) 121 | plic.io.in <> mmioXbar.io.out(1).toAXI4Lite 122 | plic.io.extra.get.intrVec := RegNext(RegNext(io.meip)) 123 | val meipSync = plic.io.extra.get.meip(0) 124 | BoringUtils.addSource(meipSync, "meip") 125 | 126 | 127 | // ILA 128 | if (p.FPGAPlatform) { 129 | def BoringUtilsConnect(sink: UInt, id: String) = { 130 | val temp = WireInit(0.U(64.W)) 131 | BoringUtils.addSink(temp, id) 132 | sink := temp 133 | } 134 | 135 | val dummy = WireInit(0.U.asTypeOf(new ILABundle)) 136 | val ila = io.ila.getOrElse(dummy) 137 | BoringUtilsConnect(ila.WBUpc ,"ilaWBUpc") 138 | BoringUtilsConnect(ila.WBUvalid ,"ilaWBUvalid") 139 | BoringUtilsConnect(ila.WBUrfWen ,"ilaWBUrfWen") 140 | BoringUtilsConnect(ila.WBUrfDest ,"ilaWBUrfDest") 141 | BoringUtilsConnect(ila.WBUrfData ,"ilaWBUrfData") 142 | BoringUtilsConnect(ila.InstrCnt ,"ilaInstrCnt") 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/main/scala/system/Prefetcher.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package system 18 | 19 | import nutcore.{NutCore, NutCoreConfig, HasNutCoreParameter, AddressSpace, Cache, CacheConfig} 20 | import bus.axi4.{AXI4, AXI4Lite} 21 | import bus.simplebus._ 22 | import utils._ 23 | 24 | import chisel3._ 25 | import chisel3.util._ 26 | import chisel3.util.experimental.BoringUtils 27 | 28 | trait HasPrefetcherParameter extends HasNutCoreParameter { 29 | val supportPrefetch = HasDcache 30 | } 31 | 32 | class Prefetcher extends Module with HasPrefetcherParameter { 33 | val io = IO(new Bundle { 34 | val in = Flipped(Decoupled(new SimpleBusReqBundle)) 35 | val out = Decoupled(new SimpleBusReqBundle) 36 | }) 37 | val getNewReq = RegInit(false.B) 38 | val prefetchReq = RegNext(io.in.bits) 39 | prefetchReq.cmd := SimpleBusCmd.prefetch 40 | prefetchReq.addr := io.in.bits.addr + XLEN.U 41 | 42 | //lastReqAddr not be initted, in vivado simulation maybe fail 43 | //val lastReqAddr = (RegEnable(io.in.bits.addr, io.in.fire)) 44 | val lastReqAddr = RegInit(0.U(AddrBits.W)) 45 | when (io.in.fire) { 46 | lastReqAddr := io.in.bits.addr 47 | } 48 | val thisReqAddr = io.in.bits.addr 49 | val lineMask = Cat(Fill(AddrBits - 6, 1.U(1.W)), 0.U(6.W)) 50 | val neqAddr = (thisReqAddr & lineMask) =/= (lastReqAddr & lineMask) 51 | 52 | when (!getNewReq) { 53 | io.out.bits <> io.in.bits 54 | io.out.valid := io.in.valid 55 | io.in.ready := !io.in.valid || io.out.fire 56 | getNewReq := io.in.fire && io.in.bits.isBurst() && neqAddr 57 | }.otherwise { 58 | io.out.bits <> prefetchReq 59 | io.out.valid := !AddressSpace.isMMIO(prefetchReq.addr) 60 | io.in.ready := false.B 61 | getNewReq := !(io.out.fire || AddressSpace.isMMIO(prefetchReq.addr)) 62 | } 63 | 64 | Debug() { 65 | printf("%d: [Prefetcher]: in(%d,%d), out(%d,%d), in.bits.addr = %x\n", 66 | GTimer(), io.in.valid, io.in.ready, io.out.valid, io.out.ready, io.in.bits.addr) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/scala/top/Settings.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package top 18 | 19 | object DefaultSettings { 20 | def apply() = Map( 21 | "MemMapBase" -> 0x0000000000000000L, 22 | "MemMapRegionBits" -> 0, 23 | "MMIOBase" -> 0x0000000040000000L, 24 | "MMIOSize" -> 0x0000000040000000L, 25 | "ResetVector" -> 0x80000000L, 26 | "NrExtIntr" -> 1, 27 | 28 | "HasL2cache" -> true, 29 | "HasPrefetch" -> true, 30 | "EnableMultiIssue" -> false, 31 | "EnableOutOfOrderExec" -> false, 32 | "HasDTLB" -> true, 33 | "HasITLB" -> true, 34 | "HasDcache" -> true, 35 | "HasIcache" -> true, 36 | "MmodeOnly" -> false, 37 | "IsRV32" -> false, 38 | 39 | "FPGAPlatform" -> false, 40 | "EnableILA" -> true, 41 | "EnableDebug" -> false, 42 | "EnableRVC" -> true 43 | ) 44 | } 45 | 46 | object PynqSettings { 47 | def apply() = Map( 48 | "FPGAPlatform" -> true, 49 | "NrExtIntr" -> 3, 50 | "ResetVector" -> 0x60000000L, 51 | "MemMapBase" -> 0x0000000010000000L, 52 | "MemMapRegionBits" -> 28, 53 | "MMIOBase" -> 0x00000000e0000000L, 54 | "MMIOSize" -> 0x0000000020000000L, 55 | "EnableDebug" -> false 56 | ) 57 | } 58 | 59 | object Axu3cgSettings { 60 | def apply() = Map( 61 | "FPGAPlatform" -> true, 62 | "NrExtIntr" -> 2, 63 | "EnableDebug" -> false 64 | ) 65 | } 66 | 67 | object PXIeSettings { 68 | def apply() = Map( 69 | "FPGAPlatform" -> true, 70 | "NrExtIntr" -> 5, 71 | "EnableDebug" -> false 72 | ) 73 | } 74 | 75 | object OOOSettings { 76 | def apply() = Map( 77 | "EnableMultiIssue" -> true, 78 | "EnableOutOfOrderExec" -> true 79 | ) 80 | } 81 | 82 | object InOrderSettings { 83 | def apply() = Map() 84 | } 85 | 86 | object EmbededSettings { 87 | def apply() = Map( 88 | "HasL2cache" -> false, 89 | "HasPrefetch" -> false, 90 | "HasDTLB" -> false, 91 | "HasITLB" -> false, 92 | "HasDcache" -> false, 93 | "HasIcache" -> false, 94 | "MmodeOnly" -> true, 95 | "IsRV32" -> true, 96 | "EnableRVC" -> false 97 | ) 98 | } 99 | 100 | object Settings { 101 | var settings: Map[String, AnyVal] = DefaultSettings() 102 | def get(field: String) = { 103 | settings(field).asInstanceOf[Boolean] 104 | } 105 | def getLong(field: String) = { 106 | settings(field).asInstanceOf[Long] 107 | } 108 | def getInt(field: String) = { 109 | settings(field).asInstanceOf[Int] 110 | } 111 | } 112 | 113 | //**************************************** 114 | // Generate RV32 core 115 | //**************************************** 116 | 117 | // 1. Enable IsRV32 118 | // 2. Set DATAWIDTH = 32 in Makefile 119 | // 3. make a fresh build 120 | 121 | 122 | //**************************************** 123 | // Instructions to boot on axu3cg 124 | //**************************************** 125 | 126 | // 1. Set FPGAmode = "axu3cg" 127 | // 2. Create a project in fpga/ 128 | // 3. Generate bitstram using vivado 129 | // 4. Copy bit-file to server:/tftpboot/axu3cg/, handle soft link of fpga.bit and power on 130 | 131 | 132 | //**************************************** 133 | // Instructions to boot on pynq 134 | //**************************************** 135 | 136 | // 1. Set FPGAmode = "pynq" 137 | // 2. Create a project in fpga/ with arg "STANDALONE=true" (no "-" in PRJ name) 138 | // 3. Generate bitstram using vivado and export a hardware description file 139 | // 4. Handle soft links in fpga/boot/build/zynq/ 140 | // fpga.bit -> bitstream generated by vivado 141 | // ps.hdf -> PRJ_PATH/PRJ.sdk/system_top_wrapper.hdf 142 | // 5. Configure FSBL_LOC variable in fpga/resource/fsbl-loader/Makefile 143 | // 6. Run bootgen, copy BOOT.BIN to SD card and power on 144 | -------------------------------------------------------------------------------- /src/main/scala/utils/BitUtils.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package utils 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | object WordShift { 23 | def apply(data: UInt, wordIndex: UInt, step: Int) = (data << (wordIndex * step.U)) 24 | } 25 | 26 | object MaskExpand { 27 | def apply(m: UInt) = Cat(m.asBools.map(Fill(8, _)).reverse) 28 | } 29 | 30 | object MaskData { 31 | def apply(oldData: UInt, newData: UInt, fullmask: UInt) = { 32 | require(oldData.getWidth == newData.getWidth) 33 | require(oldData.getWidth == fullmask.getWidth) 34 | (newData & fullmask) | (oldData & ~fullmask) 35 | } 36 | } 37 | 38 | object SignExt { 39 | def apply(a: UInt, len: Int) = { 40 | val aLen = a.getWidth 41 | val signBit = a(aLen-1) 42 | if (aLen >= len) a(len-1,0) else Cat(Fill(len - aLen, signBit), a) 43 | } 44 | } 45 | 46 | object ZeroExt { 47 | def apply(a: UInt, len: Int) = { 48 | val aLen = a.getWidth 49 | if (aLen >= len) a(len-1,0) else Cat(0.U((len - aLen).W), a) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/scala/utils/Debug.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package utils 18 | 19 | import chisel3._ 20 | import difftest.common.LogPerfControl 21 | import nutcore.NutCoreConfig 22 | import utils.LogLevel.LogLevel 23 | 24 | object LogLevel extends Enumeration { 25 | type LogLevel = Value 26 | 27 | val ALL = Value(0, "ALL ") 28 | val DEBUG = Value("DEBUG") 29 | val INFO = Value("INFO ") 30 | val WARN = Value("WARN ") 31 | val ERROR = Value("ERROR") 32 | val OFF = Value("OFF ") 33 | } 34 | 35 | object LogUtil { 36 | 37 | def control(): (Bool, UInt) = { 38 | val control = LogPerfControl() 39 | (control.logEnable, control.timer) 40 | } 41 | 42 | def apply(debugLevel: LogLevel) 43 | (prefix: Boolean, cond: Bool, pable: Printable) 44 | (implicit name: String): Any = { 45 | if (NutCoreConfig().EnableDebug){ 46 | val c = control() 47 | val commonInfo = p"[${c._2}] $name: " 48 | when (cond && c._1) { 49 | if(prefix) printf(commonInfo) 50 | printf(pable) 51 | } 52 | } 53 | } 54 | } 55 | 56 | sealed abstract class LogHelper(val logLevel: LogLevel) { 57 | 58 | def apply(cond: Bool, fmt: String, data: Bits*)(implicit name: String): Any = 59 | apply(cond, Printable.pack(fmt, data:_*)) 60 | def apply(cond: Bool, pable: Printable)(implicit name: String): Any = apply(true, cond, pable) 61 | def apply(fmt: String, data: Bits*)(implicit name: String): Any = 62 | apply(true.B, Printable.pack(fmt, data:_*)) 63 | def apply(pable: Printable)(implicit name: String): Any = apply(true.B, pable) 64 | def apply(prefix: Boolean, fmt: String, data: Bits*)(implicit name: String): Any = apply(prefix, true.B, Printable.pack(fmt, data:_*)) 65 | def apply(prefix: Boolean, pable: Printable)(implicit name: String): Any = apply(prefix, true.B, pable) 66 | def apply(prefix: Boolean, cond: Bool, fmt: String, data: Bits*)(implicit name: String): Any = 67 | apply(prefix, cond, Printable.pack(fmt, data:_*)) 68 | def apply(prefix: Boolean, cond: Bool, pable: Printable)(implicit name: String): Any = 69 | LogUtil(logLevel)(prefix, cond, pable) 70 | 71 | // NOOP/NutShell style debug 72 | def apply(flag: Boolean = NutCoreConfig().EnableDebug, cond: Bool = true.B)(body: => Unit): Any = { 73 | if(NutCoreConfig().EnhancedLog){ 74 | if(flag) { when (cond && LogUtil.control()._1) { body } } 75 | } else { 76 | if(flag) { when (cond) { body } } 77 | } 78 | } 79 | } 80 | 81 | object Debug extends LogHelper(LogLevel.DEBUG) 82 | object Info extends LogHelper(LogLevel.INFO) 83 | object Warn extends LogHelper(LogLevel.WARN) 84 | object Error extends LogHelper(LogLevel.ERROR) 85 | 86 | object ShowType { 87 | def apply[T: Manifest](t: T) = println(manifest[T]) 88 | } 89 | -------------------------------------------------------------------------------- /src/main/scala/utils/FlushableQueue.scala: -------------------------------------------------------------------------------- 1 | // https://github.com/chipsalliance/chisel3/pull/2155 is not included in edu.berkeley.cs::chisel3:3.5.0-RC1 2 | // For now, we keep this file to make CI stable 3 | 4 | package utils 5 | 6 | import chisel3._ 7 | import chisel3.util._ 8 | import chisel3.internal.naming._ // can't use chisel3_ version because of compile order 9 | 10 | class FlushableQueueIO[T <: Data](private val gen: T, entries: Int) extends Bundle { 11 | val enq = Flipped(EnqIO(gen)) 12 | val deq = Flipped(DeqIO(gen)) 13 | val count = Output(UInt(log2Ceil(entries + 1).W)) 14 | val flush = Input(Bool()) 15 | } 16 | 17 | class FlushableQueue[T <: Data](gen: T, val entries: Int, 18 | pipe: Boolean = false, flow: Boolean = false) extends Module() { 19 | val genType = gen 20 | 21 | val io = IO(new FlushableQueueIO(genType, entries)) 22 | 23 | private val ram = Mem(entries, genType) 24 | private val enq_ptr = Counter(entries) 25 | private val deq_ptr = Counter(entries) 26 | private val maybe_full = RegInit(false.B) 27 | 28 | private val ptr_match = enq_ptr.value === deq_ptr.value 29 | private val empty = ptr_match && !maybe_full 30 | private val full = ptr_match && maybe_full 31 | private val do_enq = WireInit(io.enq.fire) 32 | private val do_deq = WireInit(io.deq.fire) 33 | 34 | when (do_enq) { 35 | ram(enq_ptr.value) := io.enq.bits 36 | enq_ptr.inc() 37 | } 38 | when (do_deq) { 39 | deq_ptr.inc() 40 | } 41 | when (do_enq =/= do_deq) { 42 | maybe_full := do_enq 43 | } 44 | 45 | io.deq.valid := !empty 46 | io.enq.ready := !full 47 | io.deq.bits := ram(deq_ptr.value) 48 | 49 | if (flow) { 50 | when (io.enq.valid) { io.deq.valid := true.B } 51 | when (empty) { 52 | io.deq.bits := io.enq.bits 53 | do_deq := false.B 54 | when (io.deq.ready) { do_enq := false.B } 55 | } 56 | } 57 | 58 | if (pipe) { 59 | when (io.deq.ready) { io.enq.ready := true.B } 60 | } 61 | 62 | when (io.flush) { 63 | if (entries > 1) { 64 | enq_ptr.value := 0.U 65 | deq_ptr.value := 0.U 66 | } 67 | maybe_full := false.B 68 | } 69 | 70 | private val ptr_diff = enq_ptr.value - deq_ptr.value 71 | if (isPow2(entries)) { 72 | io.count := Cat(maybe_full && ptr_match, ptr_diff) 73 | } else { 74 | io.count := Mux(ptr_match, 75 | Mux(maybe_full, 76 | entries.asUInt, 0.U), 77 | Mux(deq_ptr.value > enq_ptr.value, 78 | entries.asUInt + ptr_diff, ptr_diff)) 79 | } 80 | } 81 | 82 | object FlushableQueue { 83 | /** Create a queue and supply a DecoupledIO containing the product. */ 84 | def apply[T <: Data](enq: ReadyValidIO[T], flush: Bool, entries: Int = 2, 85 | pipe: Boolean = false, flow: Boolean = false): DecoupledIO[T] = { 86 | if (entries == 0) { 87 | val deq = Wire(new DecoupledIO(enq.bits)) 88 | deq.valid := enq.valid 89 | deq.bits := enq.bits 90 | enq.ready := deq.ready 91 | deq 92 | } else { 93 | require(entries > 0) 94 | val q = Module(new FlushableQueue(chiselTypeOf(enq.bits), entries, pipe, flow)) 95 | q.io.enq.valid := enq.valid // not using <> so that override is allowed 96 | q.io.enq.bits := enq.bits 97 | q.io.flush := flush 98 | enq.ready := q.io.enq.ready 99 | q.io.deq 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/scala/utils/GTimer.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package utils 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | object GTimer { 23 | def apply() = { 24 | val c = RegInit(0.U(64.W)) 25 | c := c + 1.U 26 | c 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/scala/utils/Hold.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package utils 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | object HoldUnless { 23 | def apply[T <: Data](x: T, en: Bool): T = Mux(en, x, RegEnable(x, 0.U.asTypeOf(x), en)) 24 | } 25 | 26 | object ReadAndHold { 27 | def apply[T <: Data](x: Mem[T], addr: UInt, en: Bool): T = HoldUnless(x.read(addr), en) 28 | def apply[T <: Data](x: SyncReadMem[T], addr: UInt, en: Bool): T = HoldUnless(x.read(addr, en), RegNext(en)) 29 | } 30 | -------------------------------------------------------------------------------- /src/main/scala/utils/LFSR64.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package utils 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | object LFSR64 { 23 | def apply(increment: Bool = true.B): UInt = { 24 | val wide = 64 25 | val lfsr = RegInit(0x1234567887654321L.U(wide.W)) // random initial value based on simulation seed 26 | val xor = lfsr(0) ^ lfsr(1) ^ lfsr(3) ^ lfsr(4) 27 | when (increment) { 28 | lfsr := Mux(lfsr === 0.U, 1.U, Cat(xor, lfsr(wide-1,1))) 29 | } 30 | lfsr 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/scala/utils/LatencyPipe.scala: -------------------------------------------------------------------------------- 1 | // See LICENSE.Berkeley for license details. 2 | 3 | package utils 4 | 5 | import chisel3._ 6 | import chisel3.util._ 7 | 8 | class LatencyPipe[T <: Data](typ: T, latency: Int) extends Module { 9 | val io = IO(new Bundle { 10 | val in = Flipped(DecoupledIO(typ)) 11 | val out = DecoupledIO(typ) 12 | }) 13 | 14 | def doN[T](n: Int, func: T => T, in: T): T = 15 | (0 until n).foldLeft(in)((last, _) => func(last)) 16 | 17 | io.out <> doN(latency, (last: DecoupledIO[T]) => Queue(last, 1, pipe=true), io.in) 18 | } 19 | 20 | object LatencyPipe { 21 | def apply[T <: Data](in: DecoupledIO[T], latency: Int): DecoupledIO[T] = { 22 | val pipe = Module(new LatencyPipe(in.bits.cloneType, latency)) 23 | pipe.io.in <> in 24 | pipe.io.out 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/scala/utils/Lock.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package utils 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | class LockBundle extends Bundle { 23 | val lock = Input(Bool()) 24 | val unlock = Input(Bool()) 25 | val holding = Output(Bool()) 26 | } 27 | 28 | class Lock(n: Int) extends Module { 29 | val io = IO(new Bundle { 30 | val bundle = Vec(n, new LockBundle) 31 | }) 32 | 33 | val lock = RegInit(0.U(n.W)) 34 | val lockReq = VecInit(io.bundle.map(_.lock)).asUInt 35 | val unlockReq = VecInit(io.bundle.map(_.unlock)).asUInt 36 | 37 | val lockEmpty = lock === 0.U 38 | val hasLockReq = lockReq =/= 0.U 39 | val lockNext = 1.U << PriorityEncoder(lockReq) 40 | when (lockEmpty && hasLockReq) { lock := lockNext } 41 | 42 | val hasUnlockReq = unlockReq =/= 0.U 43 | assert(PopCount(unlockReq) <= 1.U, "only the lock holder can issue unlock request") 44 | assert(!(lockEmpty && hasUnlockReq), "only the lock holder can issue unlock request") 45 | assert((lock & lockReq) === 0.U, "can not issue lock request when holding the lock") 46 | when (!lockEmpty && hasUnlockReq) { 47 | assert(unlockReq === lock, "only the lock holder can issue unlock request") 48 | lock := 0.U 49 | } 50 | 51 | val holding = Mux(lockEmpty && hasLockReq, lockNext, lock) 52 | io.bundle.map(_.holding).zip(holding.asBools).map{ case (l, r) => l := r } 53 | assert(PopCount(io.bundle.map(_.holding)) <= 1.U, "there should be only one lock holder") 54 | 55 | Debug() { 56 | when (lockEmpty && hasLockReq) { printf("%d: %d acquire lock\n", GTimer(), PriorityEncoder(lockNext)) } 57 | when (!lockEmpty && hasUnlockReq) { printf("%d: %d release lock\n", GTimer(), PriorityEncoder(lock)) } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/scala/utils/LookupTree.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package utils 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | object LookupTree { 23 | def apply[T <: Data](key: UInt, mapping: Iterable[(UInt, T)]): T = 24 | Mux1H(mapping.map(p => (p._1 === key, p._2))) 25 | } 26 | 27 | object LookupTreeDefault { 28 | def apply[T <: Data](key: UInt, default: T, mapping: Iterable[(UInt, T)]): T = 29 | MuxLookup(key, default)(mapping.toSeq) 30 | } 31 | -------------------------------------------------------------------------------- /src/main/scala/utils/Pipeline.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package utils 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | object PipelineConnect { 23 | def apply[T <: Data](left: DecoupledIO[T], right: DecoupledIO[T], rightOutFire: Bool, isFlush: Bool) = { 24 | val valid = RegInit(false.B) 25 | when (rightOutFire) { valid := false.B } 26 | when (left.valid && right.ready) { valid := true.B } 27 | when (isFlush) { valid := false.B } 28 | 29 | left.ready := right.ready 30 | right.bits := RegEnable(left.bits, left.valid && right.ready) 31 | right.valid := valid //&& !isFlush 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/scala/utils/PipelineVector.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package nutcore 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | import chisel3.util.experimental.BoringUtils 22 | 23 | import utils._ 24 | 25 | object PipelineVector2Connect { 26 | def apply[T <: Data](gen: T, in1: DecoupledIO[T], in2: DecoupledIO[T], out1: DecoupledIO[T], out2: DecoupledIO[T], flush: Bool, bufferSize: Int) = { 27 | 28 | //ring buffer 29 | val dataBuffer = RegInit(VecInit(Seq.fill(bufferSize)(0.U.asTypeOf(gen)))) 30 | val ringBufferHead = RegInit(0.U(log2Up(bufferSize).W)) 31 | val ringBufferTail = RegInit(0.U(log2Up(bufferSize).W)) 32 | val ringBufferEmpty = ringBufferHead === ringBufferTail 33 | val ringBufferAllowin = (0 to 1).map(i => (ringBufferHead + (i+1).U) =/= ringBufferTail).foldRight(true.B)((sum,i)=>sum&i) 34 | 35 | //enqueue 36 | val needEnqueue = Wire(Vec(2, Bool())) 37 | needEnqueue(0) := in1.valid 38 | needEnqueue(1) := in2.valid 39 | 40 | val enqueueSize = needEnqueue(0).asUInt+&needEnqueue(1).asUInt // count(true) in needEnqueue 41 | val enqueueFire = (0 to 1).map(i => enqueueSize >= (i+1).U) 42 | 43 | val wen = in1.fire || in2.fire // i.e. ringBufferAllowin && in.valid 44 | when(wen){ 45 | when(enqueueFire(0)){dataBuffer(0.U + ringBufferHead) := Mux(needEnqueue(0), in1.bits, in2.bits)} 46 | when(enqueueFire(1)){dataBuffer(1.U + ringBufferHead) := in2.bits} 47 | ringBufferHead := ringBufferHead + enqueueSize 48 | } 49 | 50 | in1.ready := ringBufferAllowin || !in1.valid 51 | in2.ready := ringBufferAllowin || !in2.valid 52 | 53 | //dequeue socket 1 54 | val deq1_StartIndex = ringBufferTail 55 | out1.bits := dataBuffer(deq1_StartIndex) 56 | out1.valid := ringBufferHead =/= deq1_StartIndex 57 | 58 | //dequeue socket 2 59 | val deq2_StartIndex = ringBufferTail + 1.U 60 | out2.bits := dataBuffer(deq2_StartIndex) 61 | out2.valid := ringBufferHead =/= deq2_StartIndex && out1.valid 62 | 63 | //dequeue control 64 | val dequeueSize = out1.fire.asUInt +& out2.fire.asUInt 65 | val dequeueFire = dequeueSize > 0.U 66 | when(dequeueFire){ 67 | ringBufferTail := ringBufferTail + dequeueSize; 68 | } 69 | 70 | //flush control 71 | when(flush){ 72 | ringBufferHead := 0.U 73 | ringBufferTail := 0.U 74 | } 75 | 76 | Debug(){ 77 | printf("[DPQ] size %x head %x tail %x enq %x deq %x\n", (bufferSize.asUInt +& ringBufferHead.asUInt - ringBufferTail.asUInt) % bufferSize.asUInt, ringBufferHead, ringBufferTail ,enqueueSize, dequeueSize) 78 | } 79 | 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/scala/utils/RegMap.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package utils 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | import top.Settings 23 | 24 | object RegMap { 25 | def Unwritable = null 26 | def apply(addr: Int, reg: UInt, wfn: UInt => UInt = (x => x)) = (addr, (reg, wfn)) 27 | def generate(mapping: Map[Int, (UInt, UInt => UInt)], raddr: UInt, rdata: UInt, 28 | waddr: UInt, wen: Bool, wdata: UInt, wmask: UInt):Unit = { 29 | val chiselMapping = mapping.map { case (a, (r, w)) => (a.U, r, w) } 30 | rdata := LookupTree(raddr, chiselMapping.map { case (a, r, w) => (a, r) }) 31 | chiselMapping.map { case (a, r, w) => 32 | if (w != null) when (wen && waddr === a) { r := w(MaskData(r, wdata, wmask)) } 33 | } 34 | } 35 | def generate(mapping: Map[Int, (UInt, UInt => UInt)], addr: UInt, rdata: UInt, 36 | wen: Bool, wdata: UInt, wmask: UInt):Unit = generate(mapping, addr, rdata, addr, wen, wdata, wmask) 37 | } 38 | 39 | object MaskedRegMap { 40 | def Unwritable = null 41 | def NoSideEffect: UInt => UInt = (x=>x) 42 | def WritableMask = Fill(if (Settings.get("IsRV32")) 32 else 64, true.B) 43 | def UnwritableMask = 0.U(if (Settings.get("IsRV32")) 32.W else 64.W) 44 | def apply(addr: Int, reg: UInt, wmask: UInt = WritableMask, wfn: UInt => UInt = (x => x), rmask: UInt = WritableMask) = (addr, (reg, wmask, wfn, rmask)) 45 | def generate(mapping: Map[Int, (UInt, UInt, UInt => UInt, UInt)], raddr: UInt, rdata: UInt, 46 | waddr: UInt, wen: Bool, wdata: UInt):Unit = { 47 | val chiselMapping = mapping.map { case (a, (r, wm, w, rm)) => (a.U, r, wm, w, rm) } 48 | rdata := LookupTree(raddr, chiselMapping.map { case (a, r, wm, w, rm) => (a, r & rm) }) 49 | chiselMapping.map { case (a, r, wm, w, rm) => 50 | if (w != null && wm != UnwritableMask) when (wen && waddr === a) { r := w(MaskData(r, wdata, wm)) } 51 | } 52 | } 53 | def isIllegalAddr(mapping: Map[Int, (UInt, UInt, UInt => UInt, UInt)], addr: UInt):Bool = { 54 | val illegalAddr = Wire(Bool()) 55 | val chiselMapping = mapping.map { case (a, (r, wm, w, rm)) => (a.U, r, wm, w, rm) } 56 | illegalAddr := LookupTreeDefault(addr, true.B, chiselMapping.map { case (a, r, wm, w, rm) => (a, false.B) }) 57 | illegalAddr 58 | } 59 | def generate(mapping: Map[Int, (UInt, UInt, UInt => UInt, UInt)], addr: UInt, rdata: UInt, 60 | wen: Bool, wdata: UInt):Unit = generate(mapping, addr, rdata, addr, wen, wdata) 61 | } 62 | -------------------------------------------------------------------------------- /src/main/scala/utils/SRAMTemplate.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package utils 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | class SRAMBundleA(val set: Int) extends Bundle { 23 | val setIdx = Output(UInt(log2Up(set).W)) 24 | 25 | def apply(setIdx: UInt) = { 26 | this.setIdx := setIdx 27 | this 28 | } 29 | } 30 | 31 | class SRAMBundleAW[T <: Data](private val gen: T, set: Int, val way: Int = 1) extends SRAMBundleA(set) { 32 | val data = Output(gen) 33 | val waymask = if (way > 1) Some(Output(UInt(way.W))) else None 34 | 35 | def apply(data: T, setIdx: UInt, waymask: UInt) = { 36 | super.apply(setIdx) 37 | this.data := data 38 | this.waymask.map(_ := waymask) 39 | this 40 | } 41 | } 42 | 43 | class SRAMBundleR[T <: Data](private val gen: T, val way: Int = 1) extends Bundle { 44 | val data = Output(Vec(way, gen)) 45 | } 46 | 47 | class SRAMReadBus[T <: Data](private val gen: T, val set: Int, val way: Int = 1) extends Bundle { 48 | val req = Decoupled(new SRAMBundleA(set)) 49 | val resp = Flipped(new SRAMBundleR(gen, way)) 50 | 51 | def apply(valid: Bool, setIdx: UInt) = { 52 | this.req.bits.apply(setIdx) 53 | this.req.valid := valid 54 | this 55 | } 56 | } 57 | 58 | class SRAMWriteBus[T <: Data](private val gen: T, val set: Int, val way: Int = 1) extends Bundle { 59 | val req = Decoupled(new SRAMBundleAW(gen, set, way)) 60 | 61 | def apply(valid: Bool, data: T, setIdx: UInt, waymask: UInt) = { 62 | this.req.bits.apply(data = data, setIdx = setIdx, waymask = waymask) 63 | this.req.valid := valid 64 | this 65 | } 66 | } 67 | 68 | class SRAMTemplate[T <: Data](gen: T, set: Int, way: Int = 1, 69 | shouldReset: Boolean = false, holdRead: Boolean = false, singlePort: Boolean = false) extends Module { 70 | val io = IO(new Bundle { 71 | val r = Flipped(new SRAMReadBus(gen, set, way)) 72 | val w = Flipped(new SRAMWriteBus(gen, set, way)) 73 | }) 74 | 75 | val wordType = UInt(gen.getWidth.W) 76 | val array = SyncReadMem(set, Vec(way, wordType)) 77 | val (resetState, resetSet) = (WireInit(false.B), WireInit(0.U)) 78 | 79 | if (shouldReset) { 80 | val _resetState = RegInit(true.B) 81 | val (_resetSet, resetFinish) = Counter(_resetState, set) 82 | when (resetFinish) { _resetState := false.B } 83 | 84 | resetState := _resetState 85 | resetSet := _resetSet 86 | } 87 | 88 | val (ren, wen) = (io.r.req.valid, io.w.req.valid || resetState) 89 | val realRen = (if (singlePort) ren && !wen else ren) 90 | 91 | val setIdx = Mux(resetState, resetSet, io.w.req.bits.setIdx) 92 | val wdataword = Mux(resetState, 0.U.asTypeOf(wordType), io.w.req.bits.data.asUInt) 93 | val waymask = Mux(resetState, Fill(way, "b1".U), io.w.req.bits.waymask.getOrElse("b1".U)) 94 | val wdata = VecInit(Seq.fill(way)(wdataword)) 95 | when (wen) { array.write(setIdx, wdata, waymask.asBools) } 96 | 97 | val rdata = (if (holdRead) ReadAndHold(array, io.r.req.bits.setIdx, realRen) 98 | else array.read(io.r.req.bits.setIdx, realRen)).map(_.asTypeOf(gen)) 99 | io.r.resp.data := VecInit(rdata) 100 | 101 | io.r.req.ready := !resetState && (if (singlePort) !wen else true.B) 102 | io.w.req.ready := true.B 103 | 104 | Debug(false) { 105 | when (wen) { 106 | printf("%d: SRAMTemplate: write %x to idx = %d\n", GTimer(), wdata.asUInt, setIdx) 107 | } 108 | when (RegNext(realRen)) { 109 | printf("%d: SRAMTemplate: read %x at idx = %d\n", GTimer(), VecInit(rdata).asUInt, RegNext(io.r.req.bits.setIdx)) 110 | } 111 | } 112 | } 113 | 114 | class SRAMTemplateWithArbiter[T <: Data](nRead: Int, gen: T, set: Int, way: Int = 1, 115 | shouldReset: Boolean = false) extends Module { 116 | val io = IO(new Bundle { 117 | val r = Flipped(Vec(nRead, new SRAMReadBus(gen, set, way))) 118 | val w = Flipped(new SRAMWriteBus(gen, set, way)) 119 | }) 120 | 121 | val ram = Module(new SRAMTemplate(gen, set, way, shouldReset, holdRead = false, singlePort = true)) 122 | ram.io.w <> io.w 123 | 124 | val readArb = Module(new Arbiter(chiselTypeOf(io.r(0).req.bits), nRead)) 125 | readArb.io.in <> io.r.map(_.req) 126 | ram.io.r.req <> readArb.io.out 127 | 128 | // latch read results 129 | io.r.map{ case r => { 130 | r.resp.data := HoldUnless(ram.io.r.resp.data, RegNext(r.req.fire)) 131 | }} 132 | } 133 | -------------------------------------------------------------------------------- /src/main/scala/utils/StopWatch.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package utils 18 | 19 | import chisel3._ 20 | import chisel3.util._ 21 | 22 | object BoolStopWatch { 23 | def apply(start: Bool, stop: Bool, startHighPriority: Boolean = false) = { 24 | val r = RegInit(false.B) 25 | if (startHighPriority) { 26 | when (stop) { r := false.B } 27 | when (start) { r := true.B } 28 | } 29 | else { 30 | when (start) { r := true.B } 31 | when (stop) { r := false.B } 32 | } 33 | r 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/test/scala/TopMain.scala: -------------------------------------------------------------------------------- 1 | /************************************************************************************** 2 | * Copyright (c) 2020 Institute of Computing Technology, CAS 3 | * Copyright (c) 2020 University of Chinese Academy of Sciences 4 | * 5 | * NutShell is licensed under Mulan PSL v2. 6 | * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 | * You may obtain a copy of Mulan PSL v2 at: 8 | * http://license.coscl.org.cn/MulanPSL2 9 | * 10 | * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 12 | * FIT FOR A PARTICULAR PURPOSE. 13 | * 14 | * See the Mulan PSL v2 for more details. 15 | ***************************************************************************************/ 16 | 17 | package top 18 | 19 | import chisel3._ 20 | import chisel3.stage.ChiselGeneratorAnnotation 21 | import circt.stage._ 22 | import device.AXI4VGA 23 | import difftest.DifftestModule 24 | import nutcore.NutCoreConfig 25 | import sim.SimTop 26 | import system.NutShell 27 | 28 | class Top extends Module { 29 | val io = IO(new Bundle{}) 30 | val nutshell = Module(new NutShell()(NutCoreConfig())) 31 | val vga = Module(new AXI4VGA) 32 | 33 | nutshell.io := DontCare 34 | vga.io := DontCare 35 | dontTouch(nutshell.io) 36 | dontTouch(vga.io) 37 | } 38 | 39 | object TopMain extends App { 40 | def parseArgs(info: String, args: Array[String]): String = { 41 | var target = "" 42 | for (arg <- args) { if (arg.startsWith(info + "=") == true) { target = arg } } 43 | require(target != "") 44 | target.substring(info.length()+1) 45 | } 46 | val newArgs = DifftestModule.parseArgs(args) 47 | val board = parseArgs("BOARD", newArgs) 48 | val core = parseArgs("CORE", newArgs) 49 | 50 | val s = (board match { 51 | case "sim" => Nil 52 | case "pynq" => PynqSettings() 53 | case "axu3cg" => Axu3cgSettings() 54 | case "PXIe" => PXIeSettings() 55 | } ) ++ ( core match { 56 | case "inorder" => InOrderSettings() 57 | case "ooo" => OOOSettings() 58 | case "embedded"=> EmbededSettings() 59 | } ) 60 | s.foreach{Settings.settings += _} // add and overwrite DefaultSettings 61 | println("====== Settings = (" + board + ", " + core + ") ======") 62 | Settings.settings.toList.sortBy(_._1)(Ordering.String).foreach { 63 | case (f, v: Long) => 64 | println(f + " = 0x" + v.toHexString) 65 | case (f, v) => 66 | println(f + " = " + v) 67 | } 68 | 69 | val generator = if (board == "sim") { 70 | ChiselGeneratorAnnotation(() => new SimTop) 71 | } 72 | else { 73 | ChiselGeneratorAnnotation(() => new Top) 74 | } 75 | var exe_args = newArgs.filter{ 76 | value => value.forall(char => char!='=') 77 | } 78 | (new ChiselStage).execute(newArgs, Seq(generator) 79 | :+ CIRCTTargetAnnotation(CIRCTTarget.SystemVerilog) 80 | :+ FirtoolOption("--disable-annotation-unknown") 81 | ) 82 | } -------------------------------------------------------------------------------- /src/test/testcase/Makefile: -------------------------------------------------------------------------------- 1 | include $(AM_HOME)/Makefile.check 2 | .PHONY: all run clean latest $(ALL) 3 | 4 | ALL = $(basename $(notdir $(shell find ./tests -name "*.c"))) 5 | 6 | all: $(addprefix Makefile., $(ALL)) 7 | @echo "" $(ALL) 8 | 9 | $(ALL): %: Makefile.% 10 | 11 | Makefile.%: tests/%.c latest 12 | @/bin/echo -e "NAME = $*\nSRCS = $<\nLIBS += klib\ninclude $${AM_HOME}/Makefile.app" > $@ 13 | -@make -s -f $@ ARCH=$(ARCH) $(MAKECMDGOALS) 14 | -@rm -f Makefile.$* 15 | 16 | #cancel rules included by $(AM_HOME)/Makefile.check 17 | image: ; 18 | default $(MAKECMDGOALS): all ; 19 | 20 | clean: 21 | rm -rf Makefile.* build/ 22 | 23 | latest: 24 | -------------------------------------------------------------------------------- /src/test/testcase/include/runtime.h: -------------------------------------------------------------------------------- 1 | #ifndef __RUNTIME_H__ 2 | #define __RUNTIME_H__ 3 | 4 | #include 5 | 6 | static inline uint8_t inb(uintptr_t addr) { return *(volatile uint8_t *)addr; } 7 | static inline uint16_t inw(uintptr_t addr) { return *(volatile uint16_t *)addr; } 8 | static inline uint32_t inl(uintptr_t addr) { return *(volatile uint32_t *)addr; } 9 | static inline uint64_t ind(uintptr_t addr) { return *(volatile uint64_t *)addr; } 10 | 11 | static inline void outb(uintptr_t addr, uint8_t data) { *(volatile uint8_t *)addr = data; } 12 | static inline void outw(uintptr_t addr, uint16_t data) { *(volatile uint16_t *)addr = data; } 13 | static inline void outl(uintptr_t addr, uint32_t data) { *(volatile uint32_t *)addr = data; } 14 | static inline void outd(uintptr_t addr, uint64_t data) { *(volatile uint64_t *)addr = data; } 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/test/testcase/tests/dma.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "runtime.h" 4 | 5 | #define DMA_BASE 0x40003000 6 | #define DMA_DEST (DMA_BASE + 0) 7 | #define DMA_SRC (DMA_BASE + 4) 8 | #define DMA_LEN (DMA_BASE + 8) 9 | 10 | #define N 8192 11 | static int buf[N] = {}; 12 | static int buf2[N] = {}; 13 | static int buf3[N] = {}; 14 | #define SIZE (sizeof(buf)) 15 | 16 | static void dma(void *dest, const void *src, size_t n) { 17 | outl(DMA_DEST, (uint32_t)(uintptr_t)dest); 18 | outl(DMA_SRC, (uint32_t)(uintptr_t)src); 19 | printf("starting DMA with len = %d...\n", n); 20 | outl(DMA_LEN, n); 21 | 22 | printf("wait for finish...\n"); 23 | while (inl(DMA_LEN) != 0); 24 | } 25 | 26 | static inline int gen_data(int i) { 27 | return rand(); 28 | // uint8_t byte0 = (i + 0) & 0xff; 29 | // uint8_t byte1 = (i + 1) & 0xff; 30 | // uint8_t byte2 = (i + 2) & 0xff; 31 | // uint8_t byte3 = (i + 3) & 0xff; 32 | // return byte0 | (byte1 << 8) | (byte2 << 16) | (byte3 << 24); 33 | } 34 | 35 | static inline void check_buf(int *ref, int *dut, int size) { 36 | int i; 37 | for (i = 0; i < size; i ++) { 38 | if (ref[i] != dut[i]) { 39 | printf("wrong at idx = %d, right = 0x%08x, wrong = 0x%08x\n", i, ref[i], dut[i]); 40 | assert(0); 41 | } 42 | } 43 | } 44 | 45 | int main() { 46 | int i; 47 | for (i = 0; i < N; i ++) buf[i] = gen_data(i); 48 | dma(buf2, buf, SIZE); 49 | check_buf(buf, buf2, N); 50 | 51 | for (i = 0; i < N; i ++) buf3[i] = gen_data(i); 52 | dma(buf2, buf3, SIZE); 53 | check_buf(buf2, buf3, N); 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /src/test/testcase/tests/plic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "runtime.h" 4 | 5 | #define MEIP_BASE 0x40004000 6 | #define PLIC_BASE 0x3c000000 7 | #define PLIC_ENABLE (PLIC_BASE + 0x2000) 8 | #define PLIC_CLAIM (PLIC_BASE + 0x200004) 9 | 10 | int main() { 11 | uint32_t claim = inl(PLIC_CLAIM); 12 | assert(claim == 0); 13 | 14 | printf("enable meip\n"); 15 | outl(MEIP_BASE, 1); 16 | claim = inl(PLIC_CLAIM); 17 | assert(claim == 0); 18 | 19 | outl(PLIC_ENABLE, 0x2); 20 | // the interrupt is not taken in this test, 21 | // and the execution flow continues 22 | 23 | claim = inl(PLIC_CLAIM); 24 | assert(claim == 1); 25 | 26 | uint32_t claim2 = inl(PLIC_CLAIM); 27 | assert(claim2 == 0); 28 | 29 | outl(PLIC_CLAIM, claim); 30 | 31 | // MEIP_BASE is still valid 32 | claim = inl(PLIC_CLAIM); 33 | assert(claim == 1); 34 | 35 | printf("disable meip\n"); 36 | outl(MEIP_BASE, 0); 37 | printf("completion\n"); 38 | outl(PLIC_CLAIM, claim); 39 | 40 | claim = inl(PLIC_CLAIM); 41 | assert(claim == 0); 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /tools/readmemh/Makefile: -------------------------------------------------------------------------------- 1 | build/verilator-readmemh: split-readmemh.c 2 | mkdir -p $(@D) 3 | gcc -O2 -Wall -Werror -o $@ $< 4 | -------------------------------------------------------------------------------- /tools/readmemh/gen-treadle-readmemh.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) { 6 | assert(argc == 3); 7 | 8 | FILE *in = fopen(argv[1], "rb"); 9 | assert(in != NULL); 10 | 11 | FILE *out = fopen(argv[2], "w"); 12 | assert(out != NULL); 13 | 14 | int i; 15 | for (i = 0; i < 0x100000; i ++) { 16 | fprintf(out, "00\n"); 17 | } 18 | 19 | uint8_t b; 20 | int ret; 21 | while ((ret = fread(&b, 1, 1, in)) != 0) { 22 | fprintf(out, "%1x%1x\n", b >> 4, b & 0xf); 23 | } 24 | 25 | fclose(in); 26 | fclose(out); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /tools/readmemh/groupby-4byte.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) { 6 | assert(argc == 3); 7 | 8 | FILE *in = fopen(argv[1], "rb"); 9 | assert(in != NULL); 10 | 11 | FILE *out = fopen(argv[2], "w"); 12 | assert(out != NULL); 13 | 14 | char line[128]; 15 | uint32_t addr; 16 | union { 17 | uint8_t _8[4]; 18 | uint32_t _32; 19 | } data[4]; 20 | while (fgets(line, 128, in) != NULL) { 21 | if (line[0] == '@') { 22 | sscanf(line + 1, "%x", &addr); 23 | assert(addr % 4 == 0); 24 | fprintf(out, "@%08x\n", addr / 4); 25 | } 26 | else { 27 | int ret = sscanf(line, 28 | "%hhx%hhx%hhx%hhx" 29 | "%hhx%hhx%hhx%hhx" 30 | "%hhx%hhx%hhx%hhx" 31 | "%hhx%hhx%hhx%hhx", 32 | &data[0]._8[0], &data[0]._8[1], &data[0]._8[2], &data[0]._8[3], 33 | &data[1]._8[0], &data[1]._8[1], &data[1]._8[2], &data[1]._8[3], 34 | &data[2]._8[0], &data[2]._8[1], &data[2]._8[2], &data[2]._8[3], 35 | &data[3]._8[0], &data[3]._8[1], &data[3]._8[2], &data[3]._8[3]); 36 | 37 | assert(ret == EOF || ret == 4 || ret == 8 || ret == 12 || ret == 16); 38 | 39 | if (ret == EOF) continue; 40 | 41 | if (ret >= 4) fprintf(out, "%08x ", data[0]._32); 42 | if (ret >= 8) fprintf(out, "%08x ", data[1]._32); 43 | if (ret >= 12) fprintf(out, "%08x ", data[2]._32); 44 | if (ret >= 16) fprintf(out, "%08x ", data[3]._32); 45 | fprintf(out, "\n"); 46 | } 47 | } 48 | 49 | fclose(in); 50 | fclose(out); 51 | 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /tools/readmemh/split-readmemh.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | char outname [4][4096]; 7 | 8 | int main(int argc, char *argv[]) { 9 | assert(argc == 2); 10 | 11 | FILE *in = fopen(argv[1], "rb"); 12 | assert(in != NULL); 13 | 14 | strcat(stpcpy(outname[0], argv[1]), "_0"); 15 | strcat(stpcpy(outname[1], argv[1]), "_1"); 16 | strcat(stpcpy(outname[2], argv[1]), "_2"); 17 | strcat(stpcpy(outname[3], argv[1]), "_3"); 18 | 19 | FILE *out[4]; 20 | out[0] = fopen(outname[0], "w"); 21 | out[1] = fopen(outname[1], "w"); 22 | out[2] = fopen(outname[2], "w"); 23 | out[3] = fopen(outname[3], "w"); 24 | assert(out[0] != NULL && out[1] != NULL && out[2] != NULL && out[3] != NULL); 25 | 26 | char line[128]; 27 | int idx = 0; 28 | while (fgets(line, 128, in) != NULL) { 29 | if (line[0] == '@') { 30 | uint32_t addr; 31 | sscanf(line + 1, "%x", &addr); 32 | assert(addr % 4 == 0); 33 | fprintf(out[0], "\n@%08x\n", addr / 4); 34 | fprintf(out[1], "\n@%08x\n", addr / 4); 35 | fprintf(out[2], "\n@%08x\n", addr / 4); 36 | fprintf(out[3], "\n@%08x\n", addr / 4); 37 | idx = 0; 38 | } 39 | else { 40 | // remove white spaces at the end 41 | char *p = line + strlen(line) - 1; 42 | while (p >= line && (*p == ' ' || *p == '\n' || *p == '\r')) p --; 43 | p[1] = '\0'; 44 | 45 | p = line; 46 | char *byte; 47 | while ((byte = strsep(&p, " "))) { 48 | fprintf(out[idx % 4], "%s ", byte); 49 | idx ++; 50 | } 51 | 52 | if ((idx >> 2) % 16 == 0) { 53 | fprintf(out[0], "\n"); 54 | fprintf(out[1], "\n"); 55 | fprintf(out[2], "\n"); 56 | fprintf(out[3], "\n"); 57 | } 58 | } 59 | } 60 | 61 | fclose(in); 62 | fclose(out[0]); 63 | fclose(out[1]); 64 | fclose(out[2]); 65 | fclose(out[3]); 66 | 67 | return 0; 68 | } 69 | --------------------------------------------------------------------------------