├── .github ├── scripts │ ├── ExtractBuildDependenciesFromPullRequest.gawk │ ├── generateGitClones.gawk │ └── generateVersionOverrides.gawk └── workflows │ └── test.yml ├── .gitignore ├── LICENSE ├── README.md ├── auto_test.lisp ├── auto_test.py ├── build.sbt ├── delete_output.sh ├── firrtl_black_box_resource_files.f ├── imgs └── rtt.png ├── implementation.md ├── project ├── build.properties └── plugins.sbt ├── run_rtt.sh ├── scalastyle-config.xml ├── scalastyle-test-config.xml └── src ├── main └── scala │ └── Xim │ ├── AXI_Bridge.scala │ ├── AXI_crossbar.scala │ ├── AXI_interface.scala │ ├── AXI_ram.scala │ ├── AddModulePrefix.scala │ ├── CPU_Core.scala │ ├── CPU_Core_SoC.scala │ ├── CPU_EX.scala │ ├── CPU_IF.scala │ ├── Constants.scala │ ├── SoC.scala │ ├── alu.scala │ ├── branch_pred.scala │ ├── commented.scala │ ├── common.scala │ ├── csr.scala │ ├── priviledge.scala │ ├── ptw.scala │ ├── ptw_independent.scala │ ├── reg.scala │ └── tlb.scala └── test └── scala └── Xim ├── ALUMain.scala ├── ALUUnitTest.scala ├── AXI_RAM_Main.scala ├── AXI_RAM_UnitTest.scala ├── CPU_Core_Main.scala ├── CPU_Core_UnitTest.scala ├── CSR_Main.scala ├── CSR_UnitTest.scala ├── PTWMain.scala ├── PTWUnitTest.scala ├── SoC_Main.scala └── SoC_UnitTest.scala /.github/scripts/ExtractBuildDependenciesFromPullRequest.gawk: -------------------------------------------------------------------------------- 1 | /^[[:space:]]*"body": / { 2 | # Convert character sequences to character constants 3 | gsub(/\\r/, "") 4 | gsub(/\\n/, "\n") 5 | # Remove trailing punctuation 6 | gsub(/\n*",$/, "") 7 | # Look for the build dependency tag 8 | i=split($0, a, /### Build Dependencies/) 9 | if ( i != 2 ) { 10 | print "no build dependencies" 11 | exit 0 12 | } 13 | # Throw away everything up to the build dependency tag 14 | $0=a[2] 15 | # Grab the specific build dependencies 16 | i=split($0,a,/\nBuild with: /) 17 | delete a[1] 18 | # Format the individual dependencies 19 | errLines = 0 20 | depLines = 0 21 | for (i in a) { 22 | # Remove trailing text 23 | gsub(/\n.*$/, "", a[i]) 24 | n=split(a[i], d, /\s+/) 25 | switch (d[1]) { 26 | case /maven-version/ : 27 | if (n != 3) { 28 | err[errLines++]="unrecognized maven-version stanza: " a[i] "(" n ")" 29 | } 30 | break 31 | 32 | case /git-clone/ : 33 | if (n != 4) { 34 | err[errLines++]="unrecognized git-clone stanza: " a[i] "(" n ")" 35 | } 36 | break 37 | 38 | default: 39 | err[errLines++]="unrecognized build type: " d[1] " - " a[i] 40 | break 41 | 42 | } 43 | # If we don't have any errors, format this dependency line and add it 44 | # to the list of dependency lines. 45 | if (errLines == 0) { 46 | sep="" 47 | line="" 48 | for (n in d) { 49 | line=line sep d[n] 50 | sep=" " 51 | } 52 | dep[depLines++]=line 53 | } 54 | } 55 | # Print either errors (to stderr) or the dependency lines (to stdout) 56 | if (errLines == 0) { 57 | for (n in dep) { 58 | print dep[n] 59 | } 60 | } else { 61 | for (n in err) { 62 | print err[n] > "/dev/stderr" 63 | } 64 | exit 1 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /.github/scripts/generateGitClones.gawk: -------------------------------------------------------------------------------- 1 | # Generate commands to: 2 | # - clone, build, and publish dependencies, (on stdout) 3 | # - fetch corresponding shas ( on fd 3) 4 | # Specify "-v verbose=1" on the command line for verbose output (to stderr) 5 | /#/ { 6 | # Strip comments 7 | gsub(/#.*$/,"") 8 | } 9 | /git-clone/ { 10 | project=$2 11 | repo=$3 12 | tag=$4 13 | if (verbose) { 14 | print "writing clone and build commands to stdout." > "/dev/stderr" 15 | } 16 | # Generate commands to do a shallow fetch of all branches, checkout the desired ref/sha, and build and publish the jars. 17 | printf "git clone --no-single-branch --no-checkout --depth 5 %s %s && (cd %s && git checkout %s && sbt +publishLocal)\n",repo,project,project,tag 18 | # If the tag looks like a SHA, assume it is and generate a command to just echo it, 19 | # otherwise, generate a string to fetch the sha from the remote. 20 | # In either case, write the output to fd 3. 21 | if (verbose) { 22 | print "writing sha generation commands to fd 3." > "/dev/stderr" 23 | } 24 | if ( tag ~ /^[[:xdigit:]]+$/ ) { 25 | printf "echo %s\n", tag > "/dev/fd/3" 26 | } else { 27 | printf "git ls-remote --tags --heads %s %s", repo, tag > "/dev/fd/3" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.github/scripts/generateVersionOverrides.gawk: -------------------------------------------------------------------------------- 1 | # Generate suitable definitions for sbt to override default dependency 2 | # specifications in the associated build.sbt, assuming the latter has 3 | # been structured to support this. It should contain something like: 4 | # 5 | # // Provide a managed dependency on X if -DXVersion="" is supplied on the command line. 6 | # val defaultVersions = Seq( 7 | # "chisel3" -> "3.3-SNAPSHOT", 8 | # "treadle" -> "1.2-SNAPSHOT" 9 | # ) 10 | # 11 | # libraryDependencies ++= defaultVersions.map { case (dep, ver) => 12 | # "edu.berkeley.cs" %% dep % sys.props.getOrElse(dep + "Version", ver) } 13 | 14 | /#/ { 15 | # Strip comments 16 | gsub(/#.*$/,"") 17 | } 18 | /maven-version/ { 19 | # Print a series of "-DfooVersion=xxx" to override the default chisel versions in build.sbt 20 | printf "%s-D%sVersion=%s", sep, $2, $3; sep = " " 21 | } 22 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | build: 7 | name: ci 8 | runs-on: ubuntu-latest 9 | container: 10 | image: ucbbar/chisel3-tools 11 | options: --user github --entrypoint /bin/bash 12 | env: 13 | CHISEL3_REF: master 14 | FIRRTL_REF: master 15 | FIRRTL_INTERPRETER_REF: master 16 | TREADLE_REF: master 17 | CONTAINER_HOME: /home/github 18 | 19 | steps: 20 | - name: id 21 | id: id 22 | run: | 23 | uid=$(id -u) 24 | echo ::set-env name=CONTAINER_HOME::$(if [ "$uid" = "0" ]; then echo "/root"; else echo "/home/github"; fi) 25 | printenv 26 | whoami 27 | git --version 28 | pwd 29 | # Currently, sbt seems to either ignore (or doesn't see) $HOME inside the container, 30 | # and insists on using /home/ (i.e., /home/github). 31 | # Set up symbolic links so /home/gitsub/.{sbt,cache} (inside the container) are links to 32 | # the equivalent directories in $HOME (i.e, /github/home) 33 | - name: link-caches 34 | id: link-caches 35 | run: | 36 | echo "Link $CONTAINER_HOME caches to $HOME" 37 | echo mkdir -p $HOME/.cache $HOME/.ivy2 $HOME/.sbt 38 | mkdir -p $HOME/.cache $HOME/.ivy2 $HOME/.sbt 39 | echo ln -s $HOME/.cache $HOME/.ivy2 $HOME/.sbt $CONTAINER_HOME 40 | ln -s $HOME/.cache $HOME/.ivy2 $HOME/.sbt $CONTAINER_HOME 41 | echo ls -la $HOME . $CONTAINER_HOME 42 | ls -la $HOME . $CONTAINER_HOME 43 | - name: checkout 44 | uses: actions/checkout@v2 45 | with: 46 | path: repo 47 | - name: cache-sbt 48 | uses: actions/cache@v1 49 | env: 50 | cache-name: cache-sbt 51 | with: 52 | path: ~/.sbt 53 | key: build-${{ env.cache-name }}-v1 54 | restore-keys: | 55 | build-${{ env.cache-name }}- 56 | - name: cache-coursier 57 | uses: actions/cache@v1 58 | env: 59 | cache-name: cache-coursier 60 | with: 61 | path: ~/.cache 62 | key: build-${{ env.cache-name }}-v1 63 | restore-keys: | 64 | build-${{ env.cache-name }}- 65 | - name: list 66 | id: list 67 | run: | 68 | echo ls -la . repo ~/.sbt ~/.cache /home/github /home/github/.??* 69 | ls -la . repo ~/.sbt ~/.cache /home/github /home/github/.??* 70 | - name: env 71 | id: env 72 | run: | 73 | echo "cat $GITHUB_EVENT_PATH" 74 | cat $GITHUB_EVENT_PATH 75 | - name: gawk 76 | id: gawk 77 | run: | 78 | gawk -f repo/.github/scripts/ExtractBuildDependenciesFromPullRequest.gawk $GITHUB_EVENT_PATH > deps 79 | ls -l deps 80 | cat deps 81 | gawk -f repo/.github/scripts/generateGitClones.gawk deps > clones.sh 3> shas.sh 82 | cat shas.sh 83 | bash shas.sh > shas 84 | - name: cache-dependencies 85 | id: cache-dependencies 86 | uses: actions/cache@v1 87 | env: 88 | cache-name: cache-dependencies 89 | with: 90 | path: ~/.ivy2/local 91 | key: build-${{ env.cache-name }}-v1-${{ hashFiles('shas') }} 92 | - name: clone-deps 93 | id: clone-deps 94 | run: | 95 | cat clones.sh 96 | bash clones.sh 97 | if: steps.cache-dependencies.outputs.cache-hit != 'true' 98 | - name: version-deps 99 | id: version-deps 100 | run: | 101 | versionDeps=$(gawk -f repo/.github/scripts/generateVersionOverrides.gawk deps) 102 | echo "versonDeps: $versionDeps" 103 | - name: test 104 | id: test 105 | run: cat /dev/null | sbt $versionDeps +test 106 | working-directory: ./repo 107 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Project Specific stuff 2 | test_run_dir/* 3 | chenguokai.tar.gz 4 | ### tmp verilog 5 | *.fir 6 | *.v 7 | *.json 8 | 9 | ### XilinxISE template 10 | # intermediate build files 11 | *.bgn 12 | *.bit 13 | *.bld 14 | *.cmd_log 15 | *.drc 16 | *.ll 17 | *.lso 18 | *.msd 19 | *.msk 20 | *.ncd 21 | *.ngc 22 | *.ngd 23 | *.ngr 24 | *.pad 25 | *.par 26 | *.pcf 27 | *.prj 28 | *.ptwx 29 | *.rbb 30 | *.rbd 31 | *.stx 32 | *.syr 33 | *.twr 34 | *.twx 35 | *.unroutes 36 | *.ut 37 | *.xpi 38 | *.xst 39 | *_bitgen.xwbt 40 | *_envsettings.html 41 | *_map.map 42 | *_map.mrp 43 | *_map.ngm 44 | *_map.xrpt 45 | *_ngdbuild.xrpt 46 | *_pad.csv 47 | *_pad.txt 48 | *_par.xrpt 49 | *_summary.html 50 | *_summary.xml 51 | *_usage.xml 52 | *_xst.xrpt 53 | 54 | # project-wide generated files 55 | *.gise 56 | par_usage_statistics.html 57 | usage_statistics_webtalk.html 58 | webtalk.log 59 | webtalk_pn.xml 60 | 61 | # generated folders 62 | iseconfig/ 63 | xlnx_auto_0_xdb/ 64 | xst/ 65 | _ngo/ 66 | _xmsgs/ 67 | ### Eclipse template 68 | *.pydevproject 69 | .metadata 70 | .gradle 71 | bin/ 72 | tmp/ 73 | *.tmp 74 | *.bak 75 | *.swp 76 | *~.nib 77 | local.properties 78 | .settings/ 79 | .loadpath 80 | 81 | # Eclipse Core 82 | .project 83 | 84 | # External tool builders 85 | .externalToolBuilders/ 86 | 87 | # Locally stored "Eclipse launch configurations" 88 | *.launch 89 | 90 | # CDT-specific 91 | .cproject 92 | 93 | # JDT-specific (Eclipse Java Development Tools) 94 | .classpath 95 | 96 | # Java annotation processor (APT) 97 | .factorypath 98 | 99 | # PDT-specific 100 | .buildpath 101 | 102 | # sbteclipse plugin 103 | .target 104 | 105 | # TeXlipse plugin 106 | .texlipse 107 | ### C template 108 | # Object files 109 | *.o 110 | *.ko 111 | *.obj 112 | *.elf 113 | 114 | # Precompiled Headers 115 | *.gch 116 | *.pch 117 | 118 | # Libraries 119 | *.lib 120 | *.a 121 | *.la 122 | *.lo 123 | 124 | # Shared objects (inc. Windows DLLs) 125 | *.dll 126 | *.so 127 | *.so.* 128 | *.dylib 129 | 130 | # Executables 131 | *.exe 132 | *.out 133 | *.app 134 | *.i*86 135 | *.x86_64 136 | *.hex 137 | 138 | # Debug files 139 | *.dSYM/ 140 | ### SBT template 141 | # Simple Build Tool 142 | # http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html#configuring-version-control 143 | 144 | target/ 145 | lib_managed/ 146 | src_managed/ 147 | project/boot/ 148 | .history 149 | .cache 150 | ### Emacs template 151 | # -*- mode: gitignore; -*- 152 | *~ 153 | \#*\# 154 | /.emacs.desktop 155 | /.emacs.desktop.lock 156 | *.elc 157 | auto-save-list 158 | tramp 159 | .\#* 160 | 161 | # Org-mode 162 | .org-id-locations 163 | *_archive 164 | 165 | # flymake-mode 166 | *_flymake.* 167 | 168 | # eshell files 169 | /eshell/history 170 | /eshell/lastdir 171 | 172 | # elpa packages 173 | /elpa/ 174 | 175 | # reftex files 176 | *.rel 177 | 178 | # AUCTeX auto folder 179 | /auto/ 180 | 181 | # cask packages 182 | .cask/ 183 | ### Vim template 184 | [._]*.s[a-w][a-z] 185 | [._]s[a-w][a-z] 186 | *.un~ 187 | Session.vim 188 | .netrwhist 189 | *~ 190 | ### JetBrains template 191 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio 192 | 193 | *.iml 194 | 195 | ## Directory-based project format: 196 | .idea/ 197 | # if you remove the above rule, at least ignore the following: 198 | 199 | # User-specific stuff: 200 | # .idea/workspace.xml 201 | # .idea/tasks.xml 202 | # .idea/dictionaries 203 | 204 | # Sensitive or high-churn files: 205 | # .idea/dataSources.ids 206 | # .idea/dataSources.xml 207 | # .idea/sqlDataSources.xml 208 | # .idea/dynamic.xml 209 | # .idea/uiDesigner.xml 210 | 211 | # Gradle: 212 | # .idea/gradle.xml 213 | # .idea/libraries 214 | 215 | # Mongo Explorer plugin: 216 | # .idea/mongoSettings.xml 217 | 218 | ## File-based project format: 219 | *.ipr 220 | *.iws 221 | 222 | ## Plugin-specific files: 223 | 224 | # IntelliJ 225 | /out/ 226 | 227 | # mpeltonen/sbt-idea plugin 228 | .idea_modules/ 229 | 230 | # JIRA plugin 231 | atlassian-ide-plugin.xml 232 | 233 | # Crashlytics plugin (for Android Studio and IntelliJ) 234 | com_crashlytics_export_strings.xml 235 | crashlytics.properties 236 | crashlytics-build.properties 237 | ### C++ template 238 | # Compiled Object files 239 | *.slo 240 | *.lo 241 | *.o 242 | *.obj 243 | 244 | # Precompiled Headers 245 | *.gch 246 | *.pch 247 | 248 | # Compiled Dynamic libraries 249 | *.so 250 | *.dylib 251 | *.dll 252 | 253 | # Fortran module files 254 | *.mod 255 | 256 | # Compiled Static libraries 257 | *.lai 258 | *.la 259 | *.a 260 | *.lib 261 | 262 | # Executables 263 | *.exe 264 | *.out 265 | *.app 266 | ### OSX template 267 | .DS_Store 268 | .AppleDouble 269 | .LSOverride 270 | 271 | # Icon must end with two \r 272 | Icon 273 | 274 | # Thumbnails 275 | ._* 276 | 277 | # Files that might appear in the root of a volume 278 | .DocumentRevisions-V100 279 | .fseventsd 280 | .Spotlight-V100 281 | .TemporaryItems 282 | .Trashes 283 | .VolumeIcon.icns 284 | 285 | # Directories potentially created on remote AFP share 286 | .AppleDB 287 | .AppleDesktop 288 | Network Trash Folder 289 | Temporary Items 290 | .apdisk 291 | ### Xcode template 292 | # Xcode 293 | # 294 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 295 | 296 | ## Build generated 297 | build/ 298 | DerivedData 299 | 300 | ## Various settings 301 | *.pbxuser 302 | !default.pbxuser 303 | *.mode1v3 304 | !default.mode1v3 305 | *.mode2v3 306 | !default.mode2v3 307 | *.perspectivev3 308 | !default.perspectivev3 309 | xcuserdata 310 | 311 | ## Other 312 | *.xccheckout 313 | *.moved-aside 314 | *.xcuserstate 315 | ### Scala template 316 | *.class 317 | *.log 318 | 319 | # sbt specific 320 | .cache 321 | .history 322 | .lib/ 323 | dist/* 324 | target/ 325 | lib_managed/ 326 | src_managed/ 327 | project/boot/ 328 | project/plugins/project/ 329 | 330 | # Scala-IDE specific 331 | .scala_dependencies 332 | .worksheet 333 | ### Java template 334 | *.class 335 | 336 | # Mobile Tools for Java (J2ME) 337 | .mtj.tmp/ 338 | 339 | # Package Files # 340 | *.jar 341 | *.war 342 | *.ear 343 | 344 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 345 | hs_err_pid* 346 | 347 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020, Guokai Chen. All Rights Reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 1. Redistributions of source code must retain the above copyright 6 | notice, this list of conditions and the following disclaimer. 7 | 2. Redistributions in binary form must reproduce the above copyright 8 | notice, this list of conditions and the following disclaimer in the 9 | documentation and/or other materials provided with the distribution. 10 | 3. Neither the name of the Guokai Chen nor the 11 | names of its contributors may be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | 14 | IN NO EVENT SHALL Guokai Chen BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, 15 | SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING 16 | OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF Guokai Chen HAS 17 | BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | 19 | Guokai Chen SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 20 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 | PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED 22 | HEREUNDER IS PROVIDED "AS IS". Guokai Chen HAS NO OBLIGATION TO PROVIDE 23 | MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple CPU 2 | 3 | Once mb-core 4 | 5 | ## Goal 6 | 7 | Build a RISC-V64 IMZicsr processor which is capable of running RT-thread. 8 | 9 | ## Structure 10 | 11 | Two-stage pipeline (Instruction fetch and Execution) 12 | 13 | ## Logs: 14 | 15 | ### Done 16 | 17 | 2020.9.22 The very beginning instruction(addi x1, zero, 100) 18 | 19 | 2020.9.24 Branch instructions (beq zero, zero, 0x10) 20 | 21 | 2020.9.26 Introduced AXI RAM and build a simple SoC 22 | 23 | 2020.10.2 CSR related instructions 24 | 25 | 2020.10.3 Launch function tests 26 | 27 | 2020.10.6 risc-v test scripts,all RV32I tests pass 28 | 29 | 2020.10.15 RT-Thread without interrupts 30 | 31 | 2020.10.16 RT-Thread with interrupts 32 | 33 | 2020.10.26 branch predictor 34 | 35 | 2020.11.4 RV64IZicsr 36 | 37 | 2020.11.10 RTL freeze 38 | 39 | ### TODO 40 | 41 | Check [implementation.md](implementation.md) 42 | 43 | ## Run RT-Thread 44 | 45 | ![RT-Thread](./imgs/rtt.png) 46 | 47 | ### Preparation 48 | 49 | 1. Compile RT-thread with [RTT for mb-core](https://github.com/chenguokai/rtt-mbcore/tree/master/bsp/mb-core) . 50 | 2. Use `31.rtt.sh` in [tests](https://github.com/chenguokai/mbcore-tests) to generate bin file from `rtthread.elf`. 51 | 3. Adjust the load file path in AXI RAM file. 52 | 53 | ### Run 54 | 55 | Call Type Three method in SoC_Main using sbt. `i` in which is the total expected instruction cycle. 56 | 57 | ## Test framework details 58 | 59 | > Note that some paths are hard-coded, feel free to adjust if it does not fit yours. 60 | 61 | ### Type 1: any predicatable benchmark test 62 | 63 | > No longer works like below since the simulator is for RV32I while we have moved to RV64I 64 | 65 | 程序正常执行甚至发生预期的异常时,几乎不会出现前后两条指令PC值一致的情形,如此一来判定指令前进变得异常简单,只需以相邻周期PC值是否有所改变作为新指令到来判据。 66 | 使用[isa_sim](https://github.com/ultraembedded/riscv/tree/master/isa_sim) 67 | 所提供的ISA模拟器,可导出benchmark执行trace,与上述指令判断依据结合即可实现指令比对。 68 | 69 | ### Type 2: risc-v test related auto test 70 | 71 | All ISA tests from risc-v official repo will execute an `ecall` when pass or fail. Right before that, a passed test writes `1` to `a0` while a failed one writes `0`. Hence we are able to implement an auto test (`auto_test.py`). 72 | 73 | ### Type 3: any test without test feedback 74 | 75 | Type 1 without trace comparison. 76 | 77 | ## Generate verilog 78 | 79 | You may generate verilog for any non-BlackBox modules using their corresponding objects. To generate verilog for a BlackBox, use any module in which the BlackBox is used. -------------------------------------------------------------------------------- /auto_test.lisp: -------------------------------------------------------------------------------- 1 | (setq path "/Users/cgk/ownCloud/课程/一生一芯/ict/riscv-tests/isa/") 2 | (setq objcopy_1_1 "/Users/cgk/ownCloud/课程/一生一芯/ict/riscv64-unknown-elf-gcc-8.3.0-2020.04.0-x86_64-apple-darwin/bin/riscv64-unknown-elf-objcopy -O binary ") 3 | (setq objcopy_1_2 " /Users/cgk/ownCloud/课程/一生一芯/ict/test.bin.ori") 4 | (setq objcopy_2 "/Users/cgk/ownCloud/课程/一生一芯/ict/riscv64-unknown-elf-gcc-8.3.0-2020.04.0-x86_64-apple-darwin/bin/riscv64-unknown-elf-objcopy -I binary -O binary --reverse-bytes=4 /Users/cgk/ownCloud/课程/一生一芯/ict/test.bin.ori /Users/cgk/ownCloud/课程/一生一芯/ict/test.bin") 5 | (setq sbt "sbt \"test:runMain Xim.SoC_Main_Type_Two --backend-name verilator\"") 6 | (defun get_files(file_list) 7 | (setq tmp (readfile)) 8 | ;(println tmp) 9 | ;(print "debug: file_list") 10 | ;(println file_list) 11 | (cond 12 | ((eq "." tmp) (get_files file_list)) ; do not need, skip 13 | ((eq ".." tmp) (get_files file_list)) ; do not need, skip 14 | ((eq nil tmp) file_list) 15 | (t (get_files (cons tmp file_list))) 16 | ) 17 | ) 18 | 19 | (defun filter(file_list ans) 20 | (setq tmp (car file_list)) 21 | (cond 22 | ((eq tmp nil) ans) 23 | ((not (strin tmp "rv64ui-p-")) (filter (cdr file_list) ans)) 24 | ((not (strin tmp "dump")) (filter (cdr file_list) (cons tmp ans))) ; if this is not a dump 25 | (t (filter (cdr file_list) ans)) 26 | ) 27 | ) 28 | 29 | (defun append_path (file_list ans) 30 | (setq tmp (car file_list)) 31 | (cond 32 | ((eq tmp nil) ans) 33 | (t (append_path (cdr file_list) (cons (stradd path tmp) ans))) 34 | ) 35 | ) 36 | 37 | (defun test (test_path_list) 38 | (setq tmp (car test_path_list)) 39 | (cond 40 | ((eq tmp nil) 0) 41 | (t 42 | ; construct commands 43 | (println "************ New Test ************") 44 | (princ a ) 45 | (setq a (+ a 1)) 46 | (princ "th test case: ") 47 | (print tmp) 48 | (setq objcopy (stradd objcopy_1_1 tmp)) 49 | (setq objcopy (stradd objcopy objcopy_1_2)) 50 | (system objcopy) 51 | (setq objcopy objcopy_2) 52 | (system objcopy) 53 | (system sbt) 54 | (test (cdr test_path_list)) 55 | ) 56 | ) 57 | ) 58 | 59 | (setq a 1) 60 | (diropen path) 61 | (setq test_list (list)) 62 | (setq test_list (get_files test_list)) 63 | ; (println test_list) 64 | (setq ans (list)) 65 | (setq ans (filter test_list ans)) 66 | (setq tmp_list (list)) 67 | (setq ans (append_path ans tmp_list)) 68 | ; (println ans) 69 | (setq retcode (test ans)) 70 | (cond 71 | ((eq retcode 0) (println "Test all done")) 72 | (t (println "Error in test")) 73 | ) 74 | (exit 0) 75 | -------------------------------------------------------------------------------- /auto_test.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re # regular expression 3 | 4 | path = "/home/wangns/riscv-tests/isa/" #the path of compiled risc-v test 5 | 6 | files= os.listdir(path) # get all file names 7 | 8 | ans_files = [] 9 | ans_list = [] 10 | 11 | for file in files: 12 | if os.path.isdir(path + file): # remove dirs 13 | continue 14 | if re.match('.*dump', file) != None: 15 | continue 16 | #if re.match('rv64ui-p-', file) != None: 17 | if re.match('rv64si-p-supervisor', file) != None: 18 | ans_files.append(file) 19 | 20 | # print(ans_files) 21 | i = 1 22 | 23 | for file in ans_files: 24 | print("************ New Test of " + file + " ************") 25 | print(i, end = '') 26 | i = i + 1 27 | print("th test") 28 | os.system('riscv64-unknown-elf-objcopy -O binary ' + path + file + ' /home/wangns/test.bin.ori') 29 | os.system('riscv64-unknown-elf-objcopy -I binary -O binary --reverse-bytes=8 /home/wangns/test.bin.ori /home/wangns/test.bin') 30 | os.system('sbt "test:runMain Xim.SoC_Main_Type_Two --backend-name verilator"') 31 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | // See README.md for license details. 2 | 3 | def scalacOptionsVersion(scalaVersion: String): Seq[String] = { 4 | Seq() ++ { 5 | // If we're building with Scala > 2.11, enable the compile option 6 | // switch to support our anonymous Bundle definitions: 7 | // https://github.com/scala/bug/issues/10047 8 | CrossVersion.partialVersion(scalaVersion) match { 9 | case Some((2, scalaMajor: Long)) if scalaMajor < 12 => Seq() 10 | case _ => Seq("-Xsource:2.11") 11 | } 12 | } 13 | } 14 | 15 | def javacOptionsVersion(scalaVersion: String): Seq[String] = { 16 | Seq() ++ { 17 | // Scala 2.12 requires Java 8. We continue to generate 18 | // Java 7 compatible code for Scala 2.11 19 | // for compatibility with old clients. 20 | CrossVersion.partialVersion(scalaVersion) match { 21 | case Some((2, scalaMajor: Long)) if scalaMajor < 12 => 22 | Seq("-source", "1.7", "-target", "1.7") 23 | case _ => 24 | Seq("-source", "1.8", "-target", "1.8") 25 | } 26 | } 27 | } 28 | 29 | name := "chisel-module-template" 30 | 31 | version := "3.3.0" 32 | 33 | scalaVersion := "2.12.10" 34 | 35 | crossScalaVersions := Seq("2.12.10", "2.11.12") 36 | 37 | resolvers ++= Seq( 38 | Resolver.sonatypeRepo("snapshots"), 39 | Resolver.sonatypeRepo("releases") 40 | ) 41 | 42 | addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full) 43 | 44 | // Provide a managed dependency on X if -DXVersion="" is supplied on the command line. 45 | val defaultVersions = Seq( 46 | "chisel-iotesters" -> "1.4.1+", 47 | "chiseltest" -> "0.2.1+" 48 | ) 49 | 50 | libraryDependencies ++= defaultVersions.map { case (dep, ver) => 51 | "edu.berkeley.cs" %% dep % sys.props.getOrElse(dep + "Version", ver) } 52 | 53 | scalacOptions ++= scalacOptionsVersion(scalaVersion.value) 54 | 55 | javacOptions ++= javacOptionsVersion(scalaVersion.value) -------------------------------------------------------------------------------- /delete_output.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rm -rf project/project project/target target/ test_run_dir/ 3 | -------------------------------------------------------------------------------- /firrtl_black_box_resource_files.f: -------------------------------------------------------------------------------- 1 | /Users/cgk/ownCloud/课程/一生一芯/ict/chisel-template/AXI_Bridge.v -------------------------------------------------------------------------------- /imgs/rtt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Simple-XX/SimpleCPU/99898754060446dfdbc5615b5b8a97fbd316ce2c/imgs/rtt.png -------------------------------------------------------------------------------- /implementation.md: -------------------------------------------------------------------------------- 1 | # Implementation details 2 | 3 | ## Unimplemented features: 4 | 5 | 1. Supervisor and User priviledge level (along with `medeleg` and `mideleg` CSRs). 6 | 7 | 2. Writable `misa`, `mvendorid`, `marchid`, `mimpid`, `mhartid` CSRs 8 | 9 | 3. Vectored trap handling (`mtvec` MODE is hardwired to zero) 10 | 11 | 4. Page and fetch fault related exceptions (since we do not have a virtual memory system for now) 12 | 13 | 5. External exceptions (unable to determine the currect way of handling this) 14 | 15 | 6. Software exceptions (I am lazy enough) 16 | 17 | 7. break exceptions (No need if you do not need to debug) 18 | 19 | 8. MMU (WIP but not tested) 20 | 21 | ## Non-standard features: 22 | 23 | 1. CSR-mapped `mtime` and `mtimecmp` 24 | 25 | We use 0x7c0 as `mtime`, 0x7c2 as `mtimecmp` 26 | 27 | 28 | ## Implementation Documentations 29 | 30 | ### CSR related 31 | 32 | CSRRW ALU: rs1 + 0-> CSR CSR->rd 33 | CSRRS ALU: rs1 or CSR -> CSR CSR->rd 34 | CSRRC ALU: ~rs1 and CSR -> CSR CSR->rd 35 | 36 | CSRRWI: ALU: imm + 0 -> CSR CSR->rd 37 | CSRRSI: ALU: imm or CSR -> CSR CSR->rd 38 | CSRRCI: ALU: ~imm and CSR -> CSR CSR->rd 39 | 40 | ### Exception related 41 | 42 | #### Complete supported exception list 43 | 44 | 1. Machine timer interrupt 45 | 2. Instruction address misaligned 46 | 3. Illegal instruction 47 | 4. Load address misaligned 48 | 5. Store address misaligned 49 | 6. Environmental call from M mode 50 | 51 | #### IF identified exceptions: 52 | 53 | 1. Instruction address misaligned 54 | 55 | #### EX indentified exceptions: 56 | 57 | 1. Machine timer interrupt 58 | 2. Illegal instruction 59 | 3. Load address misaligned 60 | 4. Store address misaligned 61 | 5. Environmental call from M mode 62 | 63 | #### Design Notes 64 | 65 | We currently replace an instruction following the branch taken with a NOP-like instruction. 66 | This is fine with the normal user instructions already. While for an exception related condition, it may cause some 67 | weird conditions like mepc is written with an unexpected instruction. 68 | For our naive design, an instruction follwing the branch will not trigger any exception itself 69 | so we do not handle exceptions. For the external exceptions, we will handle them when we are out of this condition 70 | 71 | ### Virtual Memory Ralated 72 | 73 | As long as there are no tlb related definiations in RISC-V spec, I will design my own tlb format for internal usage. 74 | 75 | #### TLB entry format 76 | 77 | **sv39 mode only** 78 | 79 | | page size | VPN | PPN | DAGUXWRV | 80 | | --------- | ---- | ------ | -------- | 81 | | 2 | 27 | 44 | 8 | 82 | 83 | ##### page size 84 | 85 | 0: 4KB record 86 | 1: 2MB record 87 | 2: 1GB record 88 | 3: reserved 89 | 90 | ##### DAGUXWRY 91 | 92 | Not implemented for now 93 | 94 | ##### Translation process: 95 | We divide VPN into three part: VPN2(9) VPN1(9) VPN0(9), PPN into three part: PPN2(26) PPN1(9) PPN0(9). 96 | 97 | Vaddr(11, 0) -> always keep untouched 98 | 99 | **4KB record**:Vaddr(38, 12) -> throw to match, Paddr: PPN2 || PPN1 || PPN(0) || Vaddr(11, 0) 100 | 101 | **2MB record**:Vaddr(38, 21) -> throw to match, Vaddr(20, 12) keep untouched, Paddr: PPN2 || PPN1 || Vaddr(20, 0) 102 | 103 | **1GB record**:Vaddr(38, 30) -> throw to match, Vaddr(29, 12) keep untouched, Paddr: PPN2 || Vaddr(29, 0) 104 | 105 | TLB retire algorithm: loop queue 106 | 107 | 108 | ### W suffix instructions in RV64I 109 | 110 | Note that we cannot always simply pass 64 bit srcs to ALU and expect the lower word satisfy the W suffix requirement. 111 | 112 | ADDIW: ok -> currently implemented as no W 113 | SLLIW: ok -> currently implemented as no W 114 | SRLIW: NOT OK (higher bits may come in) -> implemented 115 | SRAIW: NOT OK (higher bits affect sig) -> implemented 116 | ADDW: ok -> currently implemented as no W 117 | SUBW: ok -> currently implemented as no W 118 | SLLW: ok -> currently implemented as no W 119 | SRLW: NOT OK (higher bits may come in) -> implemented 120 | SRAW: NOT OK (higher bits affect sig) -> implemented 121 | 122 | ### Memory related design 123 | 124 | Inst and data sram-like => MMIO ? AXI_MEM : AXI_MMIO 125 | 126 | todo: add a cross bar for PTW -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | <<<<<<< HEAD 2 | sbt.version = 1.3.10 3 | ======= 4 | sbt.version = 1.3.13 5 | >>>>>>> refactor 6 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | logLevel := Level.Warn 2 | -------------------------------------------------------------------------------- /run_rtt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sbt 'test:runMain Xim.SoC_Main_Type_Three --backend-name verilator' 3 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /scalastyle-test-config.xml: -------------------------------------------------------------------------------- 1 | 2 | Scalastyle configuration for Chisel3 unit tests 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 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | No lines ending with a ; 66 | 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 | |\|\||&&|:=|<>|<=|>=|!=|===|<<|>>|##|unary_(~|\-%?|!))$]]> 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /src/main/scala/Xim/AXI_Bridge.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import chisel3._ 4 | import chisel3.util.HasBlackBoxInline 5 | 6 | 7 | class AXI_Bridge(width: Int = 64) extends BlackBox with HasBlackBoxInline { 8 | val io = IO(Flipped(new AXI_interface { 9 | val clock = Output(Clock()) 10 | val reset = Output(Reset()) 11 | // CPU side 12 | 13 | // inst sram-like 14 | val inst_req = Output(UInt(1.W)) 15 | val inst_wr = Output(UInt(1.W)) 16 | val inst_size = Output(UInt(2.W)) 17 | val inst_addr = Output(UInt(width.W)) 18 | val inst_wdata = Output(UInt(width.W)) 19 | val inst_rdata = Input(UInt(width.W)) 20 | val inst_addr_ok = Input(UInt(1.W)) 21 | val inst_data_ok = Input(UInt(1.W)) 22 | // data sram-like 23 | val data_req = Output(UInt(1.W)) 24 | val data_wr = Output(UInt(1.W)) 25 | val data_size = Output(UInt(2.W)) 26 | val data_addr = Output(UInt(width.W)) 27 | val data_wdata = Output(UInt(width.W)) 28 | val data_rdata = Input(UInt(width.W)) 29 | val data_addr_ok = Input(UInt(1.W)) 30 | val data_data_ok = Input(UInt(1.W)) 31 | 32 | // AXI side is automatically included in AXI_interface 33 | })) 34 | setInline("AXI_Bridge.v", 35 | s""" 36 | module AXI_Bridge 37 | ( 38 | input clock, 39 | input reset, 40 | 41 | //inst sram-like 42 | input inst_req , 43 | input inst_wr , 44 | input [1 :0] inst_size , 45 | input [63:0] inst_addr , 46 | input [63:0] inst_wdata , 47 | output [63:0] inst_rdata , 48 | output inst_addr_ok , 49 | output inst_data_ok , 50 | 51 | //data sram-like 52 | input data_req , 53 | input data_wr , 54 | input [1 :0] data_size , 55 | input [63:0] data_addr , 56 | input [63:0] data_wdata , 57 | output [63:0] data_rdata , 58 | output data_addr_ok , 59 | output data_data_ok , 60 | 61 | //axi 62 | //ar 63 | output [3 :0] arid , 64 | output [63:0] araddr , 65 | output [7 :0] arlen , 66 | output [2 :0] arsize , 67 | output [1 :0] arburst , 68 | output [1 :0] arlock , 69 | output [3 :0] arcache , 70 | output [2 :0] arprot , 71 | output arvalid , 72 | input arready , 73 | input aruser , 74 | input [3:0] arqos , 75 | //r 76 | input [3 :0] rid , 77 | input [63:0] rdata , 78 | input [1 :0] rresp , 79 | input rlast , 80 | input rvalid , 81 | output rready , 82 | output ruser , 83 | //aw 84 | output [3 :0] awid , 85 | output [63:0] awaddr , 86 | output [7 :0] awlen , 87 | output [2 :0] awsize , 88 | output [1 :0] awburst , 89 | output [1 :0] awlock , 90 | output [3 :0] awcache , 91 | output [2 :0] awprot , 92 | output awvalid , 93 | input awready , 94 | input awuser , 95 | input [3:0] awqos , 96 | //w 97 | output [3 :0] wid , 98 | output [63:0] wdata , 99 | output [7 :0] wstrb , 100 | output wlast , 101 | output wvalid , 102 | input wready , 103 | //b 104 | input [3 :0] bid , 105 | input [1 :0] bresp , 106 | input bvalid , 107 | output bready , 108 | output buser 109 | ); 110 | 111 | 112 | assign ruser = 1'b0; 113 | assign buser = 1'b0; 114 | 115 | wire resetn = !reset; 116 | //addr 117 | reg do_req; 118 | reg do_req_or; //req is inst or data;1:data,0:inst 119 | reg do_wr_r; 120 | reg [1 :0] do_size_r; 121 | reg [63:0] do_addr_r; 122 | reg [63:0] do_wdata_r; 123 | wire data_back; 124 | 125 | assign inst_addr_ok = !do_req&&!data_req; 126 | assign data_addr_ok = !do_req; 127 | always @(posedge clock) 128 | begin 129 | do_req <= !resetn ? 1'b0 : 130 | (inst_req||data_req)&&!do_req ? 1'b1 : 131 | data_back ? 1'b0 : do_req; 132 | do_req_or <= !resetn ? 1'b0 : 133 | !do_req ? data_req : do_req_or; 134 | 135 | do_wr_r <= data_req&&data_addr_ok ? data_wr : 136 | inst_req&&inst_addr_ok ? inst_wr : do_wr_r; 137 | do_size_r <= data_req&&data_addr_ok ? data_size : 138 | inst_req&&inst_addr_ok ? inst_size : do_size_r; 139 | do_addr_r <= data_req&&data_addr_ok ? data_addr : 140 | inst_req&&inst_addr_ok ? inst_addr : do_addr_r; 141 | do_wdata_r <= data_req&&data_addr_ok ? data_wdata : 142 | inst_req&&inst_addr_ok ? inst_wdata :do_wdata_r; 143 | end 144 | 145 | //inst sram-like 146 | assign inst_data_ok = do_req&&!do_req_or&&data_back; 147 | assign data_data_ok = do_req&& do_req_or&&data_back; 148 | assign inst_rdata = rdata; 149 | assign data_rdata = rdata; 150 | 151 | //---axi 152 | reg addr_rcv; 153 | reg wdata_rcv; 154 | 155 | assign data_back = addr_rcv && (rvalid&&rready||bvalid&&bready); 156 | always @(posedge clock) 157 | begin 158 | addr_rcv <= !resetn ? 1'b0 : 159 | arvalid&&arready ? 1'b1 : 160 | awvalid&&awready ? 1'b1 : 161 | data_back ? 1'b0 : addr_rcv; 162 | wdata_rcv <= !resetn ? 1'b0 : 163 | wvalid&&wready ? 1'b1 : 164 | data_back ? 1'b0 : wdata_rcv; 165 | end 166 | //ar 167 | assign arid = 4'd0; 168 | assign araddr = do_addr_r; 169 | assign arlen = 8'd0; 170 | assign arsize = do_size_r; 171 | assign arburst = 2'd0; 172 | assign arlock = 2'd0; 173 | assign arcache = 4'd0; 174 | assign arprot = 3'd0; 175 | assign arvalid = do_req&&!do_wr_r&&!addr_rcv; 176 | //r 177 | assign rready = 1'b1; 178 | 179 | //aw 180 | assign awid = 4'd0; 181 | assign awaddr = do_addr_r; 182 | assign awlen = 8'd0; 183 | assign awsize = do_size_r; 184 | assign awburst = 2'd0; 185 | assign awlock = 2'd0; 186 | assign awcache = 4'd0; 187 | assign awprot = 3'd0; 188 | assign awvalid = do_req&&do_wr_r&&!addr_rcv; 189 | //w 190 | assign wid = 4'd0; 191 | assign wdata = do_wdata_r; 192 | assign wstrb = do_size_r==2'd0 ? 8'b00000001< to CPU Core 25 | val s_axi_awid = Input(UInt((S_COUNT * S_ID_WIDTH).W)) 26 | val s_axi_awaddr = Input(UInt((S_COUNT * ADDR_WIDTH).W)) 27 | val s_axi_awlen = Input(UInt((S_COUNT * 8).W)) 28 | val s_axi_awsize = Input(UInt((S_COUNT * 3).W)) 29 | val s_axi_awburst = Input(UInt((S_COUNT * 2).W)) 30 | val s_axi_awlock = Input(UInt(S_COUNT.W)) 31 | val s_axi_awcache = Input(UInt((S_COUNT * 4).W)) 32 | val s_axi_awprot = Input(UInt((S_COUNT * 3).W)) 33 | val s_axi_awqos = Input(UInt((S_COUNT * 4).W)) 34 | val s_axi_awuser = Input(UInt((S_COUNT * AWUSER_WIDTH).W)) 35 | val s_axi_awvalid = Input(UInt((S_COUNT).W)) 36 | val s_axi_awready = Output(UInt((S_COUNT).W)) 37 | val s_axi_wdata = Input(UInt((S_COUNT * DATA_WIDTH).W)) 38 | val s_axi_wstrb = Input(UInt((S_COUNT * STRB_WIDTH).W)) 39 | val s_axi_wlast = Input(UInt((S_COUNT).W)) 40 | val s_axi_wuser = Input(UInt((S_COUNT * WUSER_WIDTH).W)) 41 | val s_axi_wvalid = Input(UInt((S_COUNT).W)) 42 | val s_axi_wready = Output(UInt((S_COUNT).W)) 43 | val s_axi_bid = Output(UInt((S_COUNT * S_ID_WIDTH).W)) 44 | val s_axi_bresp = Output(UInt((S_COUNT * 2).W)) 45 | val s_axi_buser = Output(UInt((S_COUNT * BUSER_WIDTH).W)) 46 | val s_axi_bvalid = Output(UInt((S_COUNT).W)) 47 | val s_axi_bready = Input(UInt((S_COUNT).W)) 48 | val s_axi_arid = Input(UInt((S_COUNT * S_ID_WIDTH).W)) 49 | val s_axi_araddr = Input(UInt((S_COUNT * ADDR_WIDTH).W)) 50 | val s_axi_arlen = Input(UInt((S_COUNT * 8).W)) 51 | val s_axi_arsize = Input(UInt((S_COUNT * 3).W)) 52 | val s_axi_arburst = Input(UInt((S_COUNT * 2).W)) 53 | val s_axi_arlock = Input(UInt((S_COUNT).W)) 54 | val s_axi_arcache = Input(UInt((S_COUNT * 4).W)) 55 | val s_axi_arprot = Input(UInt((S_COUNT * 3).W)) 56 | val s_axi_arqos = Input(UInt((S_COUNT * 4).W)) 57 | val s_axi_aruser = Input(UInt((S_COUNT * ARUSER_WIDTH).W)) 58 | val s_axi_arvalid = Input(UInt((S_COUNT).W)) 59 | val s_axi_arready = Output(UInt((S_COUNT).W)) 60 | val s_axi_rid = Output(UInt((S_COUNT * S_ID_WIDTH).W)) 61 | val s_axi_rdata = Output(UInt((S_COUNT * DATA_WIDTH).W)) 62 | val s_axi_rresp = Output(UInt((S_COUNT * 2).W)) 63 | val s_axi_rlast = Output(UInt((S_COUNT).W)) 64 | val s_axi_ruser = Output(UInt((S_COUNT * RUSER_WIDTH).W)) 65 | val s_axi_rvalid = Output(UInt((S_COUNT).W)) 66 | val s_axi_rready = Input(UInt(S_COUNT.W)) 67 | 68 | // master -> to AXI RAM and MMIO 69 | val m_axi_awid = Output(UInt((M_COUNT * M_ID_WIDTH).W)) 70 | val m_axi_awaddr = Output(UInt((M_COUNT * ADDR_WIDTH).W)) 71 | val m_axi_awlen = Output(UInt((M_COUNT * 8).W)) 72 | val m_axi_awsize = Output(UInt((M_COUNT * 3).W)) 73 | val m_axi_awburst = Output(UInt((M_COUNT * 2).W)) 74 | val m_axi_awlock = Output(UInt(M_COUNT.W)) 75 | val m_axi_awcache = Output(UInt((M_COUNT * 4).W)) 76 | val m_axi_awprot = Output(UInt((M_COUNT * 3).W)) 77 | val m_axi_awqos = Output(UInt((M_COUNT * 4).W)) 78 | val m_axi_awregion = Output(UInt((M_COUNT * 4).W)) 79 | val m_axi_awuser = Output(UInt((M_COUNT * AWUSER_WIDTH).W)) 80 | val m_axi_awvalid = Output(UInt((M_COUNT).W)) 81 | val m_axi_awready = Input(UInt((M_COUNT).W)) 82 | val m_axi_wdata = Output(UInt((M_COUNT * DATA_WIDTH).W)) 83 | val m_axi_wstrb = Output(UInt((M_COUNT * STRB_WIDTH).W)) 84 | val m_axi_wlast = Output(UInt((M_COUNT).W)) 85 | val m_axi_wuser = Output(UInt((M_COUNT * WUSER_WIDTH).W)) 86 | val m_axi_wvalid = Output(UInt((M_COUNT).W)) 87 | val m_axi_wready = Input(UInt((M_COUNT).W)) 88 | val m_axi_bid = Input(UInt((M_COUNT * M_ID_WIDTH).W)) 89 | val m_axi_bresp = Input(UInt((M_COUNT * 2).W)) 90 | val m_axi_buser = Input(UInt((M_COUNT * BUSER_WIDTH).W)) 91 | val m_axi_bvalid = Input(UInt((M_COUNT).W)) 92 | val m_axi_bready = Output(UInt((M_COUNT).W)) 93 | val m_axi_arid = Output(UInt((M_COUNT * M_ID_WIDTH).W)) 94 | val m_axi_araddr = Output(UInt((M_COUNT * ADDR_WIDTH).W)) 95 | val m_axi_arlen = Output(UInt((M_COUNT * 8).W)) 96 | val m_axi_arsize = Output(UInt((M_COUNT * 3).W)) 97 | val m_axi_arburst = Output(UInt((M_COUNT * 2).W)) 98 | val m_axi_arlock = Output(UInt((M_COUNT).W)) 99 | val m_axi_arcache = Output(UInt((M_COUNT * 4).W)) 100 | val m_axi_arprot = Output(UInt((M_COUNT * 3).W)) 101 | val m_axi_arqos = Output(UInt((M_COUNT * 4).W)) 102 | val m_axi_arregion = Output(UInt((M_COUNT * 4).W)) 103 | val m_axi_aruser = Output(UInt((M_COUNT * ARUSER_WIDTH).W)) 104 | val m_axi_arvalid = Output(UInt((M_COUNT).W)) 105 | val m_axi_arready = Input(UInt((M_COUNT).W)) 106 | val m_axi_rid = Input(UInt((M_COUNT * M_ID_WIDTH).W)) 107 | val m_axi_rdata = Input(UInt((M_COUNT * DATA_WIDTH).W)) 108 | val m_axi_rresp = Input(UInt((M_COUNT * 2).W)) 109 | val m_axi_rlast = Input(UInt((M_COUNT).W)) 110 | val m_axi_ruser = Input(UInt((M_COUNT * RUSER_WIDTH).W)) 111 | val m_axi_rvalid = Input(UInt((M_COUNT).W)) 112 | val m_axi_rready = Output(UInt(M_COUNT.W)) 113 | 114 | } 115 | 116 | class axi_crossbar extends BlackBox with HasBlackBoxResource { 117 | val io = IO(new Crossbar_interface { 118 | val clock = Input(Clock()) 119 | val reset = Input(Reset()) 120 | }) 121 | setResource("/axi_crossbar.v") 122 | } 123 | -------------------------------------------------------------------------------- /src/main/scala/Xim/AXI_interface.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import chisel3._ 4 | 5 | class AXI_interface extends Bundle { 6 | private val data_width = 64 7 | private val addr_width = 64 // 1 Megabyte should be enough for us 8 | private val wstrb_width = data_width / 8 9 | private val id_width = 8 10 | val awid = Input(UInt(data_width.W)) 11 | val awaddr = Input(UInt(addr_width.W)) 12 | val awlen = Input(UInt(8.W)) 13 | val awsize = Input(UInt(3.W)) 14 | val awburst = Input(UInt(2.W)) 15 | val awlock = Input(UInt(1.W)) 16 | val awcache = Input(UInt(4.W)) 17 | val awprot = Input(UInt(3.W)) 18 | val awvalid = Input(UInt(1.W)) 19 | val awready = Output(UInt(1.W)) 20 | val awuser = Output(UInt(1.W)) 21 | val awqos = Output(UInt(4.W)) 22 | val wdata = Input(UInt(data_width.W)) 23 | val wstrb = Input(UInt(wstrb_width.W)) 24 | val wlast = Input(UInt(1.W)) 25 | val wvalid = Input(UInt(1.W)) 26 | val wready = Output(UInt(1.W)) 27 | val bid = Output(UInt(id_width.W)) 28 | val bresp = Output(UInt(2.W)) 29 | val bvalid = Output(UInt(1.W)) 30 | val bready = Input(UInt(1.W)) 31 | val buser = Input(UInt(1.W)) 32 | val arid = Input(UInt(id_width.W)) 33 | val araddr = Input(UInt(addr_width.W)) 34 | val arlen = Input(UInt(8.W)) 35 | val arsize = Input(UInt(3.W)) 36 | val arburst = Input(UInt(2.W)) 37 | val arlock = Input(UInt(1.W)) 38 | val arcache = Input(UInt(4.W)) 39 | val arprot = Input(UInt(3.W)) 40 | val arvalid = Input(UInt(1.W)) 41 | val arready = Output(UInt(1.W)) 42 | val aruser = Output(UInt(1.W)) 43 | val arqos = Output(UInt(4.W)) 44 | val rid = Output(UInt(id_width.W)) 45 | val rdata = Output(UInt(data_width.W)) 46 | val rresp = Output(UInt(2.W)) 47 | val rlast = Output(UInt(1.W)) 48 | val rvalid = Output(UInt(1.W)) 49 | val rready = Input(UInt(1.W)) 50 | val ruser = Input(UInt(1.W)) 51 | } -------------------------------------------------------------------------------- /src/main/scala/Xim/AXI_ram.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import chisel3._ 4 | import chisel3.util.HasBlackBoxInline 5 | 6 | class AXI_lite_interface extends Bundle { 7 | private val data_width = 64 8 | private val addr_width = 64 // 1 Megabyte should be enough for us 9 | private val wstrb_width = data_width / 8 10 | private val id_width = 8 11 | val awaddr = Input(UInt(addr_width.W)) 12 | val awprot = Input(UInt(3.W)) 13 | val awvalid = Input(UInt(1.W)) 14 | val awready = Output(UInt(1.W)) 15 | val wdata = Input(UInt(data_width.W)) 16 | val wstrb = Input(UInt(wstrb_width.W)) 17 | val wvalid = Input(UInt(1.W)) 18 | val wready = Output(UInt(1.W)) 19 | val bresp = Output(UInt(2.W)) 20 | val bvalid = Output(UInt(1.W)) 21 | val bready = Input(UInt(1.W)) 22 | val araddr = Input(UInt(addr_width.W)) 23 | val arprot = Input(UInt(3.W)) 24 | val arvalid = Input(UInt(1.W)) 25 | val arready = Output(UInt(1.W)) 26 | val rdata = Output(UInt(data_width.W)) 27 | val rresp = Output(UInt(2.W)) 28 | val rvalid = Output(UInt(1.W)) 29 | val rready = Input(UInt(1.W)) 30 | } 31 | 32 | class AXI_fake_serial extends Module { 33 | private val data_width = 64 34 | private val addr_width = 20 // 1 Megabyte should be enough for us 35 | private val wstrb_width = data_width / 8 36 | private val id_width = 8 37 | val io = IO( new Bundle() { 38 | // we only listen to the write channel 39 | val awaddr = Input(UInt(addr_width.W)) 40 | val awvalid = Input(UInt(1.W)) 41 | val wvalid = Input(UInt(1.W)) 42 | val wdata = Input(UInt(data_width.W)) 43 | }) 44 | val serial_valid = RegInit(0.U(1.W)) 45 | 46 | when (io.awaddr === 0x80000.U && io.awvalid === 1.U) { 47 | serial_valid := 1.U 48 | } .elsewhen (io.wvalid === 1.U) { 49 | // after finishing the transaction 50 | serial_valid := 0.U 51 | } 52 | 53 | when (serial_valid === 1.U && io.wvalid === 1.U) { 54 | printf("%c", io.wdata(7, 0)) 55 | } 56 | } 57 | 58 | class AXI_ram extends BlackBox with HasBlackBoxInline { 59 | val io = IO(new AXI_interface { 60 | val clock = Input(Clock()) 61 | val reset = Input(Reset()) 62 | }) 63 | 64 | setInline("AXIRAM.v", 65 | s""" 66 | module AXI_ram # 67 | ( 68 | // Width of data bus in bits 69 | parameter DATA_WIDTH = 64, 70 | // Width of address bus in bits 71 | parameter ADDR_WIDTH = 20, 72 | // Width of wstrb (width of data bus in words) 73 | parameter STRB_WIDTH = (DATA_WIDTH/8), 74 | // Width of ID signal 75 | parameter ID_WIDTH = 8, 76 | // Extra pipeline register on output 77 | parameter PIPELINE_OUTPUT = 0 78 | ) 79 | ( 80 | input wire clock, 81 | input wire reset, 82 | 83 | input wire [ID_WIDTH-1:0] awid, 84 | input wire [ADDR_WIDTH-1:0] awaddr, 85 | input wire [7:0] awlen, 86 | input wire [2:0] awsize, 87 | input wire [1:0] awburst, 88 | input wire awlock, 89 | input wire [3:0] awcache, 90 | input wire [2:0] awprot, 91 | input wire awvalid, 92 | output wire awready, 93 | output wire awuser, 94 | output wire [3:0] awqos, 95 | input wire [DATA_WIDTH-1:0] wdata, 96 | input wire [STRB_WIDTH-1:0] wstrb, 97 | input wire wlast, 98 | input wire wvalid, 99 | output wire wready, 100 | output wire [ID_WIDTH-1:0] bid, 101 | output wire [1:0] bresp, 102 | output wire bvalid, 103 | input wire bready, 104 | input wire buser, 105 | input wire [ID_WIDTH-1:0] arid, 106 | input wire [ADDR_WIDTH-1:0] araddr, 107 | input wire [7:0] arlen, 108 | input wire [2:0] arsize, 109 | input wire [1:0] arburst, 110 | input wire arlock, 111 | input wire [3:0] arcache, 112 | input wire [2:0] arprot, 113 | input wire arvalid, 114 | output wire arready, 115 | output wire aruser, 116 | output wire [3:0] arqos, 117 | output wire [ID_WIDTH-1:0] rid, 118 | output wire [DATA_WIDTH-1:0] rdata, 119 | output wire [1:0] rresp, 120 | output wire rlast, 121 | output wire rvalid, 122 | input wire rready, 123 | input wire ruser 124 | ); 125 | 126 | assign awuser = 1'b0; 127 | assign awqos = 4'b0; 128 | assign aruser = 1'b0; 129 | assign arqos = 4'b0; 130 | 131 | parameter VALID_ADDR_WIDTH = ADDR_WIDTH - 3; 132 | parameter WORD_WIDTH = STRB_WIDTH; 133 | parameter WORD_SIZE = DATA_WIDTH/WORD_WIDTH; 134 | 135 | // bus width assertions 136 | initial begin 137 | end 138 | 139 | localparam [0:0] 140 | READ_STATE_IDLE = 1'd0, 141 | READ_STATE_BURST = 1'd1; 142 | 143 | reg [0:0] read_state_reg = READ_STATE_IDLE, read_state_next; 144 | 145 | localparam [1:0] 146 | WRITE_STATE_IDLE = 2'd0, 147 | WRITE_STATE_BURST = 2'd1, 148 | WRITE_STATE_RESP = 2'd2; 149 | 150 | reg [1:0] write_state_reg = WRITE_STATE_IDLE, write_state_next; 151 | 152 | reg mem_wr_en; 153 | reg mem_rd_en; 154 | 155 | reg [ID_WIDTH-1:0] read_id_reg = {ID_WIDTH{1'b0}}, read_id_next; 156 | reg [ADDR_WIDTH-1:0] read_addr_reg = {ADDR_WIDTH{1'b0}}, read_addr_next; 157 | reg [7:0] read_count_reg = 8'd0, read_count_next; 158 | reg [2:0] read_size_reg = 3'd0, read_size_next; 159 | reg [1:0] read_burst_reg = 2'd0, read_burst_next; 160 | reg [ID_WIDTH-1:0] write_id_reg = {ID_WIDTH{1'b0}}, write_id_next; 161 | reg [ADDR_WIDTH-1:0] write_addr_reg = {ADDR_WIDTH{1'b0}}, write_addr_next; 162 | reg [7:0] write_count_reg = 8'd0, write_count_next; 163 | reg [2:0] write_size_reg = 3'd0, write_size_next; 164 | reg [1:0] write_burst_reg = 2'd0, write_burst_next; 165 | 166 | reg awready_reg = 1'b0, awready_next; 167 | reg wready_reg = 1'b0, wready_next; 168 | reg [ID_WIDTH-1:0] bid_reg = {ID_WIDTH{1'b0}}, bid_next; 169 | reg bvalid_reg = 1'b0, bvalid_next; 170 | reg arready_reg = 1'b0, arready_next; 171 | reg [ID_WIDTH-1:0] rid_reg = {ID_WIDTH{1'b0}}, rid_next; 172 | reg [DATA_WIDTH-1:0] rdata_reg = {DATA_WIDTH{1'b0}}, rdata_next; 173 | reg rlast_reg = 1'b0, rlast_next; 174 | reg rvalid_reg = 1'b0, rvalid_next; 175 | reg [ID_WIDTH-1:0] rid_pipe_reg = {ID_WIDTH{1'b0}}; 176 | reg [DATA_WIDTH-1:0] rdata_pipe_reg = {DATA_WIDTH{1'b0}}; 177 | reg rlast_pipe_reg = 1'b0; 178 | reg rvalid_pipe_reg = 1'b0; 179 | 180 | // (* RAM_STYLE="BLOCK" *) 181 | reg [DATA_WIDTH-1:0] mem[(2**VALID_ADDR_WIDTH)-1:0]; 182 | 183 | wire [VALID_ADDR_WIDTH-1:0] awaddr_valid = awaddr >> (ADDR_WIDTH - VALID_ADDR_WIDTH); 184 | wire [VALID_ADDR_WIDTH-1:0] araddr_valid = araddr >> (ADDR_WIDTH - VALID_ADDR_WIDTH); 185 | wire [VALID_ADDR_WIDTH-1:0] read_addr_valid = read_addr_reg >> (ADDR_WIDTH - VALID_ADDR_WIDTH); 186 | wire [VALID_ADDR_WIDTH-1:0] write_addr_valid = write_addr_reg >> (ADDR_WIDTH - VALID_ADDR_WIDTH); 187 | 188 | assign awready = awready_reg; 189 | assign wready = wready_reg; 190 | assign bid = bid_reg; 191 | assign bresp = 2'b00; 192 | assign bvalid = bvalid_reg; 193 | assign arready = arready_reg; 194 | assign rid = PIPELINE_OUTPUT ? rid_pipe_reg : rid_reg; 195 | assign rdata = PIPELINE_OUTPUT ? rdata_pipe_reg : rdata_reg; 196 | assign rresp = 2'b00; 197 | assign rlast = PIPELINE_OUTPUT ? rlast_pipe_reg : rlast_reg; 198 | assign rvalid = PIPELINE_OUTPUT ? rvalid_pipe_reg : rvalid_reg; 199 | 200 | integer i, j, mem_file; 201 | 202 | initial begin 203 | // two nested loops for smaller number of iterations per loop 204 | // workaround for synthesizer complaints about large loop counts 205 | for (i = 0; i < 2**VALID_ADDR_WIDTH; i = i + 2**(VALID_ADDR_WIDTH/2)) begin 206 | for (j = i; j < i + 2**(VALID_ADDR_WIDTH/2); j = j + 1) begin 207 | mem[j] = 0; 208 | end 209 | end 210 | // mem[0] = 32'h863; mem[1] = 32'h06400093; mem[2] = 32'h00000013; mem[3] = 32'h00000013; mem[4] = 32'h00102023; mem[5] = 32'h00002103; 211 | // mem[6] = 32'h00f00093; mem[7] = 32'h34101073; mem[8] = 32'h34109073; mem[9] = 32'h34186073; mem[10] = 32'h341020f3; 212 | //mem_file = $$fopen("/home/wangns/rtt-mbcore/bsp/mb-core/rtthread_reversed.bin", "r"); 213 | mem_file = $$fopen("/home/wangns/test.bin", "r"); 214 | $$fread(mem, mem_file); 215 | end 216 | 217 | always @* begin 218 | write_state_next = WRITE_STATE_IDLE; 219 | 220 | mem_wr_en = 1'b0; 221 | 222 | write_id_next = write_id_reg; 223 | write_addr_next = write_addr_reg; 224 | write_count_next = write_count_reg; 225 | write_size_next = write_size_reg; 226 | write_burst_next = write_burst_reg; 227 | 228 | awready_next = 1'b0; 229 | wready_next = 1'b0; 230 | bid_next = bid_reg; 231 | bvalid_next = bvalid_reg && !bready; 232 | 233 | case (write_state_reg) 234 | WRITE_STATE_IDLE: begin 235 | awready_next = 1'b1; 236 | 237 | if (awready && awvalid) begin 238 | write_id_next = awid; 239 | write_addr_next = awaddr; 240 | write_count_next = awlen; 241 | write_size_next = awsize < 2 ? awsize : 2; 242 | write_burst_next = awburst; 243 | 244 | awready_next = 1'b0; 245 | wready_next = 1'b1; 246 | write_state_next = WRITE_STATE_BURST; 247 | end else begin 248 | write_state_next = WRITE_STATE_IDLE; 249 | end 250 | end 251 | WRITE_STATE_BURST: begin 252 | wready_next = 1'b1; 253 | 254 | if (wready && wvalid) begin 255 | mem_wr_en = 1'b1; 256 | if (write_burst_reg != 2'b00) begin 257 | write_addr_next = write_addr_reg + (1 << write_size_reg); 258 | end 259 | write_count_next = write_count_reg - 1; 260 | if (write_count_reg > 0) begin 261 | write_state_next = WRITE_STATE_BURST; 262 | end else begin 263 | wready_next = 1'b0; 264 | if (bready || !bvalid) begin 265 | bid_next = write_id_reg; 266 | bvalid_next = 1'b1; 267 | awready_next = 1'b1; 268 | write_state_next = WRITE_STATE_IDLE; 269 | end else begin 270 | write_state_next = WRITE_STATE_RESP; 271 | end 272 | end 273 | end else begin 274 | write_state_next = WRITE_STATE_BURST; 275 | end 276 | end 277 | WRITE_STATE_RESP: begin 278 | if (bready || !bvalid) begin 279 | bid_next = write_id_reg; 280 | bvalid_next = 1'b1; 281 | awready_next = 1'b1; 282 | write_state_next = WRITE_STATE_IDLE; 283 | end else begin 284 | write_state_next = WRITE_STATE_RESP; 285 | end 286 | end 287 | endcase 288 | end 289 | 290 | always @(posedge clock) begin 291 | if (reset) begin 292 | write_state_reg <= WRITE_STATE_IDLE; 293 | awready_reg <= 1'b0; 294 | wready_reg <= 1'b0; 295 | bvalid_reg <= 1'b0; 296 | end else begin 297 | write_state_reg <= write_state_next; 298 | awready_reg <= awready_next; 299 | wready_reg <= wready_next; 300 | bvalid_reg <= bvalid_next; 301 | end 302 | 303 | write_id_reg <= write_id_next; 304 | write_addr_reg <= write_addr_next; 305 | write_count_reg <= write_count_next; 306 | write_size_reg <= write_size_next; 307 | write_burst_reg <= write_burst_next; 308 | 309 | bid_reg <= bid_next; 310 | 311 | for (i = 0; i < WORD_WIDTH; i = i + 1) begin 312 | if (mem_wr_en & wstrb[i]) begin 313 | mem[write_addr_valid][WORD_SIZE*i +: WORD_SIZE] <= wdata[WORD_SIZE*i +: WORD_SIZE]; 314 | end 315 | end 316 | end 317 | 318 | always @* begin 319 | read_state_next = READ_STATE_IDLE; 320 | 321 | mem_rd_en = 1'b0; 322 | 323 | rid_next = rid_reg; 324 | rlast_next = rlast_reg; 325 | rvalid_next = rvalid_reg && !(rready || (PIPELINE_OUTPUT && !rvalid_pipe_reg)); 326 | 327 | read_id_next = read_id_reg; 328 | read_addr_next = read_addr_reg; 329 | read_count_next = read_count_reg; 330 | read_size_next = read_size_reg; 331 | read_burst_next = read_burst_reg; 332 | 333 | arready_next = 1'b0; 334 | 335 | case (read_state_reg) 336 | READ_STATE_IDLE: begin 337 | arready_next = 1'b1; 338 | 339 | if (arready && arvalid) begin 340 | read_id_next = arid; 341 | read_addr_next = araddr; 342 | read_count_next = arlen; 343 | read_size_next = arsize < 2 ? arsize : 2; 344 | read_burst_next = arburst; 345 | 346 | arready_next = 1'b0; 347 | read_state_next = READ_STATE_BURST; 348 | end else begin 349 | read_state_next = READ_STATE_IDLE; 350 | end 351 | end 352 | READ_STATE_BURST: begin 353 | if (rready || (PIPELINE_OUTPUT && !rvalid_pipe_reg) || !rvalid_reg) begin 354 | mem_rd_en = 1'b1; 355 | rvalid_next = 1'b1; 356 | rid_next = read_id_reg; 357 | rlast_next = read_count_reg == 0; 358 | if (read_burst_reg != 2'b00) begin 359 | read_addr_next = read_addr_reg + (1 << read_size_reg); 360 | end 361 | read_count_next = read_count_reg - 1; 362 | if (read_count_reg > 0) begin 363 | read_state_next = READ_STATE_BURST; 364 | end else begin 365 | arready_next = 1'b1; 366 | read_state_next = READ_STATE_IDLE; 367 | end 368 | end else begin 369 | read_state_next = READ_STATE_BURST; 370 | end 371 | end 372 | endcase 373 | end 374 | 375 | always @(posedge clock) begin 376 | if (reset) begin 377 | read_state_reg <= READ_STATE_IDLE; 378 | arready_reg <= 1'b0; 379 | rvalid_reg <= 1'b0; 380 | rvalid_pipe_reg <= 1'b0; 381 | end else begin 382 | read_state_reg <= read_state_next; 383 | arready_reg <= arready_next; 384 | rvalid_reg <= rvalid_next; 385 | 386 | if (!rvalid_pipe_reg || rready) begin 387 | rvalid_pipe_reg <= rvalid_reg; 388 | end 389 | end 390 | 391 | read_id_reg <= read_id_next; 392 | read_addr_reg <= read_addr_next; 393 | read_count_reg <= read_count_next; 394 | read_size_reg <= read_size_next; 395 | read_burst_reg <= read_burst_next; 396 | 397 | rid_reg <= rid_next; 398 | rlast_reg <= rlast_next; 399 | 400 | if (mem_rd_en) begin 401 | rdata_reg <= mem[read_addr_valid]; 402 | end 403 | 404 | if (!rvalid_pipe_reg || rready) begin 405 | rid_pipe_reg <= rid_reg; 406 | rdata_pipe_reg <= rdata_reg; 407 | rlast_pipe_reg <= rlast_reg; 408 | end 409 | end 410 | 411 | endmodule 412 | """.stripMargin 413 | ) 414 | } 415 | 416 | /* 417 | Origin copyright of this AXI RAM file: 418 | 419 | Copyright (c) 2018 Alex Forencich 420 | 421 | Permission is hereby granted, free of charge, to any person obtaining a copy 422 | of this software and associated documentation files (the "Software"), to deal 423 | in the Software without restriction, including without limitation the rights 424 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 425 | copies of the Software, and to permit persons to whom the Software is 426 | furnished to do so, subject to the following conditions: 427 | 428 | The above copyright notice and this permission notice shall be included in 429 | all copies or substantial portions of the Software. 430 | 431 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 432 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY 433 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 434 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 435 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 436 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 437 | THE SOFTWARE. 438 | */ -------------------------------------------------------------------------------- /src/main/scala/Xim/AddModulePrefix.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import firrtl._ 4 | import firrtl.annotations.NoTargetAnnotation 5 | import firrtl.ir._ 6 | import firrtl.stage.TransformManager.TransformDependency 7 | 8 | case class ModulePrefixAnnotation(prefix: String) extends NoTargetAnnotation 9 | 10 | class AddModulePrefix extends Transform with DependencyAPIMigration { 11 | 12 | override def prerequisites: Seq[TransformDependency] = firrtl.stage.Forms.ChirrtlForm 13 | 14 | override protected def execute(state: CircuitState): CircuitState = { 15 | val c = state.circuit 16 | 17 | val prefix = state.annotations.collectFirst { 18 | case ModulePrefixAnnotation(p) => p 19 | }.get 20 | 21 | def onStmt(s: Statement): Statement = s match { 22 | case DefInstance(info, name, module) => 23 | DefInstance(info, name, prefix + module) 24 | case other => 25 | other.mapStmt(onStmt) 26 | } 27 | 28 | def onModule(m: DefModule): DefModule = { 29 | val newMod = m.mapStmt(onStmt) 30 | newMod match { 31 | case Module(info, name, ports, body) => 32 | Module(info, prefix + name, ports, body) 33 | case ExtModule(info, name, ports, defname, params) => 34 | ExtModule(info, prefix+name, ports, defname, params) 35 | } 36 | } 37 | val newCircuit = c.mapModule(onModule) 38 | state.copy(newCircuit.copy(main = prefix + newCircuit.main)) 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/scala/Xim/CPU_Core.scala: -------------------------------------------------------------------------------- 1 | 2 | package Xim 3 | 4 | import chisel3._ 5 | 6 | class CPU_Core(val rv_width: Int = 64, inSOC: Boolean = false) extends Module { 7 | val io = IO(new Bundle { 8 | val axi_mem = Flipped(new AXI_interface) 9 | val axi_mmio = Flipped(new AXI_interface) 10 | // for debug purpose 11 | val reg_wen = Output(UInt(1.W)) 12 | val reg_wdata = Output(UInt(rv_width.W)) 13 | val reg_waddr = Output(UInt(5.W)) 14 | val es_instr = Output(UInt(32.W)) 15 | val es_pc = Output(UInt(rv_width.W)) 16 | val es_reg_a0 = Output(UInt(rv_width.W)) 17 | }) 18 | val inst_addr = Wire(UInt(rv_width.W)) 19 | val inst_req_valid = Wire(UInt(1.W)) 20 | val inst_req_ack = Wire(UInt(1.W)) 21 | 22 | val inst_data = Wire(UInt(rv_width.W)) 23 | val inst_valid = Wire(UInt(1.W)) 24 | val inst_ack = Wire(UInt(1.W)) 25 | 26 | val data_addr = Wire(UInt(rv_width.W)) 27 | val data_write_mem = Wire(UInt(1.W)) 28 | val data_read_mem = Wire(UInt(1.W)) 29 | val data_write_mmio = Wire(UInt(1.W)) 30 | val data_read_mmio = Wire(UInt(1.W)) 31 | val data_size = Wire(UInt(2.W)) 32 | 33 | val data_write_data = Wire(UInt(rv_width.W)) 34 | 35 | val data_req_ack = Wire(UInt(1.W)) 36 | 37 | val data_read_data = Wire(UInt(rv_width.W)) 38 | val data_read_valid = Wire(UInt(1.W)) 39 | val data_data_ack = Wire(UInt(1.W)) 40 | 41 | val IF_Stage = Module(new CPU_IF(rv_width)) 42 | inst_addr := IF_Stage.io.inst_addr 43 | inst_req_valid := IF_Stage.io.inst_req_valid 44 | IF_Stage.io.inst_req_ack := inst_req_ack 45 | IF_Stage.io.inst_data := inst_data 46 | IF_Stage.io.inst_valid := inst_valid 47 | inst_ack := IF_Stage.io.inst_ack 48 | 49 | val EX_Stage = Module(new CPU_EX(rv_width)) 50 | data_addr := EX_Stage.io.data_addr 51 | data_write_mem := EX_Stage.io.data_write_mem 52 | data_read_mem := EX_Stage.io.data_read_mem 53 | data_write_mmio := EX_Stage.io.data_write_mmio 54 | data_read_mmio := EX_Stage.io.data_read_mmio 55 | data_size := EX_Stage.io.data_size 56 | data_write_data := EX_Stage.io.data_write_data 57 | EX_Stage.io.data_req_ack := data_req_ack 58 | EX_Stage.io.data_read_data := data_read_data 59 | EX_Stage.io.data_read_valid := data_read_valid 60 | data_data_ack := EX_Stage.io.data_data_ack 61 | 62 | 63 | EX_Stage.io.fs_pc := IF_Stage.io.fs_pc 64 | EX_Stage.io.fs_inst := IF_Stage.io.fs_inst 65 | EX_Stage.io.fs_ex := IF_Stage.io.fs_ex 66 | EX_Stage.io.fs_excode := IF_Stage.io.fs_excode 67 | EX_Stage.io.fs_to_es_valid := IF_Stage.io.fs_to_es_valid 68 | EX_Stage.io.es_next_branch := IF_Stage.io.es_next_branch 69 | 70 | IF_Stage.io.inst_reload := EX_Stage.io.inst_reload 71 | IF_Stage.io.es_allowin := EX_Stage.io.es_allowin 72 | IF_Stage.io.br_valid := EX_Stage.io.br_valid 73 | IF_Stage.io.br_target := EX_Stage.io.br_target 74 | IF_Stage.io.ex_valid := EX_Stage.io.ex_valid 75 | IF_Stage.io.ex_target := EX_Stage.io.ex_target 76 | 77 | val PrivModule = Module(new PriviledgeSignal) 78 | val CSRModule = Module(new CSRSignal) 79 | PrivModule.io.es_valid := EX_Stage.io.es_inst_valid 80 | PrivModule.io.es_ex_work := CSRModule.io.es_ex_work 81 | PrivModule.io.mret_work := CSRModule.io.mret_work 82 | PrivModule.io.sret_work := CSRModule.io.sret_work 83 | PrivModule.io.mstatus_mpp := CSRModule.io.mstatus_mpp 84 | PrivModule.io.sstatus_spp := CSRModule.io.sstatus_spp 85 | CSRModule.io.priv_level := PrivModule.io.priv_level 86 | PrivModule.io.deleg_trap := CSRModule.io.deleg_trap 87 | EX_Stage.io.priv_level := PrivModule.io.priv_level 88 | 89 | EX_Stage.io.mepc := CSRModule.io.mepc 90 | EX_Stage.io.sepc := CSRModule.io.sepc 91 | CSRModule.io.es_new_instr := EX_Stage.io.new_instr 92 | CSRModule.io.es_ex := EX_Stage.io.ex_valid 93 | CSRModule.io.es_excode := EX_Stage.io.csr_excode 94 | CSRModule.io.es_pc := EX_Stage.io.es_pc 95 | CSRModule.io.es_instr := EX_Stage.io.es_instr 96 | CSRModule.io.es_csr := EX_Stage.io.es_csr_inst 97 | CSRModule.io.inst_reserved := EX_Stage.io.csr_inst_reserved 98 | CSRModule.io.inst_reload_r := EX_Stage.io.inst_reload 99 | CSRModule.io.inst_mret := EX_Stage.io.es_inst_mret 100 | CSRModule.io.inst_sret := EX_Stage.io.es_inst_sret 101 | CSRModule.io.data_addr := EX_Stage.io.data_addr 102 | CSRModule.io.Csr_num := EX_Stage.io.csr_number 103 | EX_Stage.io.csr_read_data := CSRModule.io.csr_read_data 104 | CSRModule.io.csr_write_data := EX_Stage.io.csr_write_data 105 | EX_Stage.io.csr_timer_int := CSRModule.io.timer_int 106 | EX_Stage.io.mstatus_tsr := CSRModule.io.mstatus_tsr 107 | EX_Stage.io.trap_entry := CSRModule.io.trap_entry 108 | EX_Stage.io.illegal_csr := CSRModule.io.illegal_csr 109 | 110 | val branch_predicter = Module(new branch_pred) 111 | 112 | IF_Stage.io.next_branch := branch_predicter.io.IF_next_branch 113 | branch_predicter.io.EX_new_instr := EX_Stage.io.branch_new_instr 114 | branch_predicter.io.EX_br_taken := EX_Stage.io.branch_br_taken 115 | 116 | // debug part 117 | io.reg_waddr := EX_Stage.io.es_reg_waddr 118 | io.reg_wdata := EX_Stage.io.es_reg_wdata 119 | io.reg_wen := EX_Stage.io.es_reg_wen 120 | io.es_instr := EX_Stage.io.es_instr 121 | io.es_pc := EX_Stage.io.es_pc 122 | io.es_reg_a0 := EX_Stage.io.es_reg_a0 123 | 124 | val CPU_Bridge = Module(new AXI_Bridge(64)) 125 | CPU_Bridge.io.clock := clock 126 | CPU_Bridge.io.reset := reset 127 | 128 | CPU_Bridge.io.inst_req := inst_req_valid & ~IF_Stage.io.inst_req_mmio 129 | CPU_Bridge.io.inst_wr := 0.U 130 | CPU_Bridge.io.inst_size := 2.U 131 | CPU_Bridge.io.inst_addr := inst_addr 132 | CPU_Bridge.io.inst_wdata := 0.U 133 | 134 | CPU_Bridge.io.data_req := data_write_mem | data_read_mem 135 | CPU_Bridge.io.data_wr := data_write_mem 136 | CPU_Bridge.io.data_size := data_size 137 | CPU_Bridge.io.data_addr := data_addr 138 | CPU_Bridge.io.data_wdata := data_write_data 139 | 140 | 141 | val MMIO_Bridge = Module(new AXI_Bridge(64)) 142 | 143 | MMIO_Bridge.io.clock := clock 144 | MMIO_Bridge.io.reset := reset 145 | 146 | MMIO_Bridge.io.inst_req := inst_req_valid & IF_Stage.io.inst_req_mmio // do not send any request with inst for now 147 | MMIO_Bridge.io.inst_wr := 0.U 148 | MMIO_Bridge.io.inst_size := 2.U 149 | MMIO_Bridge.io.inst_addr := inst_addr 150 | MMIO_Bridge.io.inst_wdata := 0.U 151 | 152 | inst_req_ack := (IF_Stage.io.inst_req_mmio & MMIO_Bridge.io.inst_addr_ok) | (~IF_Stage.io.inst_req_mmio & CPU_Bridge.io.inst_addr_ok) 153 | inst_valid := (IF_Stage.io.inst_req_mmio & MMIO_Bridge.io.inst_data_ok) | (~IF_Stage.io.inst_req_mmio & CPU_Bridge.io.inst_data_ok) 154 | 155 | MMIO_Bridge.io.data_req := data_write_mmio | data_read_mmio 156 | MMIO_Bridge.io.data_wr := data_write_mmio 157 | MMIO_Bridge.io.data_size := data_size 158 | MMIO_Bridge.io.data_addr := data_addr 159 | MMIO_Bridge.io.data_wdata := data_write_data 160 | 161 | when (EX_Stage.io.is_mmio === 1.U) { 162 | data_read_data := MMIO_Bridge.io.data_rdata 163 | } .otherwise { 164 | data_read_data := CPU_Bridge.io.data_rdata 165 | } 166 | 167 | when (IF_Stage.io.inst_req_mmio === 1.U) { 168 | inst_data := MMIO_Bridge.io.inst_rdata 169 | } .otherwise { 170 | inst_data := CPU_Bridge.io.inst_rdata 171 | } 172 | 173 | data_req_ack := (EX_Stage.io.is_mmio & MMIO_Bridge.io.data_addr_ok) | (~EX_Stage.io.is_mmio & CPU_Bridge.io.data_addr_ok) 174 | data_read_valid := (EX_Stage.io.is_mmio & MMIO_Bridge.io.data_data_ok) | (~EX_Stage.io.is_mmio & CPU_Bridge.io.data_data_ok) 175 | 176 | io.axi_mem.awid := CPU_Bridge.io.awid 177 | io.axi_mem.awaddr := CPU_Bridge.io.awaddr 178 | io.axi_mem.awlen := CPU_Bridge.io.awlen 179 | io.axi_mem.awsize := CPU_Bridge.io.awsize 180 | io.axi_mem.awburst := CPU_Bridge.io.awburst 181 | io.axi_mem.awlock := CPU_Bridge.io.awlock 182 | io.axi_mem.awcache := CPU_Bridge.io.awcache 183 | io.axi_mem.awprot := CPU_Bridge.io.awprot 184 | io.axi_mem.awvalid := CPU_Bridge.io.awvalid 185 | CPU_Bridge.io.awready := io.axi_mem.awready 186 | io.axi_mem.wdata := CPU_Bridge.io.wdata 187 | io.axi_mem.wstrb := CPU_Bridge.io.wstrb 188 | io.axi_mem.wlast := CPU_Bridge.io.wlast 189 | io.axi_mem.wvalid := CPU_Bridge.io.wvalid 190 | CPU_Bridge.io.wready := io.axi_mem.wready 191 | CPU_Bridge.io.bid := io.axi_mem.bid 192 | CPU_Bridge.io.bresp := io.axi_mem.bresp 193 | CPU_Bridge.io.bvalid := io.axi_mem.bvalid 194 | io.axi_mem.bready := CPU_Bridge.io.bready 195 | io.axi_mem.buser := 0.U 196 | io.axi_mem.arid := CPU_Bridge.io.arid 197 | io.axi_mem.araddr := CPU_Bridge.io.araddr 198 | io.axi_mem.arlen := CPU_Bridge.io.arlen 199 | io.axi_mem.arsize := CPU_Bridge.io.arsize 200 | io.axi_mem.arburst := CPU_Bridge.io.arburst 201 | io.axi_mem.arlock := CPU_Bridge.io.arlock 202 | io.axi_mem.arcache := CPU_Bridge.io.arcache 203 | io.axi_mem.arprot := CPU_Bridge.io.arcache 204 | io.axi_mem.arvalid := CPU_Bridge.io.arvalid 205 | CPU_Bridge.io.arready := io.axi_mem.arready 206 | CPU_Bridge.io.rid := io.axi_mem.rid 207 | CPU_Bridge.io.rdata := io.axi_mem.rdata 208 | CPU_Bridge.io.rresp := io.axi_mem.rresp 209 | CPU_Bridge.io.rlast := io.axi_mem.rlast 210 | CPU_Bridge.io.rvalid := io.axi_mem.rvalid 211 | io.axi_mem.rready := CPU_Bridge.io.rready 212 | io.axi_mem.ruser := 0.U 213 | 214 | io.axi_mmio.awid := MMIO_Bridge.io.awid 215 | io.axi_mmio.awaddr := MMIO_Bridge.io.awaddr 216 | io.axi_mmio.awlen := MMIO_Bridge.io.awlen 217 | io.axi_mmio.awsize := MMIO_Bridge.io.awsize 218 | io.axi_mmio.awburst := MMIO_Bridge.io.awburst 219 | io.axi_mmio.awlock := MMIO_Bridge.io.awlock 220 | io.axi_mmio.awcache := MMIO_Bridge.io.awcache 221 | io.axi_mmio.awprot := MMIO_Bridge.io.awprot 222 | io.axi_mmio.awvalid := MMIO_Bridge.io.awvalid 223 | MMIO_Bridge.io.awready := io.axi_mmio.awready 224 | io.axi_mmio.wdata := MMIO_Bridge.io.wdata 225 | io.axi_mmio.wstrb := MMIO_Bridge.io.wstrb 226 | io.axi_mmio.wlast := MMIO_Bridge.io.wlast 227 | io.axi_mmio.wvalid := MMIO_Bridge.io.wvalid 228 | MMIO_Bridge.io.wready := io.axi_mmio.wready 229 | MMIO_Bridge.io.bid := io.axi_mmio.bid 230 | MMIO_Bridge.io.bresp := io.axi_mmio.bresp 231 | MMIO_Bridge.io.bvalid := io.axi_mmio.bvalid 232 | io.axi_mmio.bready := MMIO_Bridge.io.bready 233 | io.axi_mmio.buser := 0.U 234 | io.axi_mmio.arid := MMIO_Bridge.io.arid 235 | io.axi_mmio.araddr := MMIO_Bridge.io.araddr 236 | io.axi_mmio.arlen := MMIO_Bridge.io.arlen 237 | io.axi_mmio.arsize := MMIO_Bridge.io.arsize 238 | io.axi_mmio.arburst := MMIO_Bridge.io.arburst 239 | io.axi_mmio.arlock := MMIO_Bridge.io.arlock 240 | io.axi_mmio.arcache := MMIO_Bridge.io.arcache 241 | io.axi_mmio.arprot := MMIO_Bridge.io.arcache 242 | io.axi_mmio.arvalid := MMIO_Bridge.io.arvalid 243 | MMIO_Bridge.io.arready := io.axi_mmio.arready 244 | MMIO_Bridge.io.rid := io.axi_mmio.rid 245 | MMIO_Bridge.io.rdata := io.axi_mmio.rdata 246 | MMIO_Bridge.io.rresp := io.axi_mmio.rresp 247 | MMIO_Bridge.io.rlast := io.axi_mmio.rlast 248 | MMIO_Bridge.io.rvalid := io.axi_mmio.rvalid 249 | io.axi_mmio.rready := MMIO_Bridge.io.rready 250 | io.axi_mmio.ruser := 0.U 251 | } 252 | 253 | object CPU_Core extends App { 254 | chisel3.Driver.execute(args, () => new CPU_Core) 255 | } -------------------------------------------------------------------------------- /src/main/scala/Xim/CPU_Core_SoC.scala: -------------------------------------------------------------------------------- 1 | 2 | package Xim 3 | 4 | import chisel3._ 5 | import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} 6 | import firrtl.stage.RunFirrtlTransformAnnotation 7 | 8 | class CPU_Core_SoC(val rv_width: Int = 64, inSOC: Boolean = false) extends Module { 9 | val io = IO(new Bundle { 10 | val meip = Input(UInt(1.W)) 11 | val mem = Flipped(new AXI_interface) 12 | val mmio = Flipped(new AXI_lite_interface) 13 | }) 14 | val inst_addr = Wire(UInt(rv_width.W)) 15 | val inst_req_valid = Wire(UInt(1.W)) 16 | val inst_req_ack = Wire(UInt(1.W)) 17 | 18 | val inst_data = Wire(UInt(rv_width.W)) 19 | val inst_valid = Wire(UInt(1.W)) 20 | val inst_ack = Wire(UInt(1.W)) 21 | 22 | val data_addr = Wire(UInt(rv_width.W)) 23 | val data_write_mem = Wire(UInt(1.W)) 24 | val data_read_mem = Wire(UInt(1.W)) 25 | val data_write_mmio = Wire(UInt(1.W)) 26 | val data_read_mmio = Wire(UInt(1.W)) 27 | val data_size = Wire(UInt(2.W)) 28 | 29 | val data_write_data = Wire(UInt(rv_width.W)) 30 | 31 | val data_req_ack = Wire(UInt(1.W)) 32 | 33 | val data_read_data = Wire(UInt(rv_width.W)) 34 | val data_read_valid = Wire(UInt(1.W)) 35 | val data_data_ack = Wire(UInt(1.W)) 36 | 37 | val IF_Stage = Module(new CPU_IF(rv_width)) 38 | inst_addr := IF_Stage.io.inst_addr 39 | inst_req_valid := IF_Stage.io.inst_req_valid 40 | IF_Stage.io.inst_req_ack := inst_req_ack 41 | IF_Stage.io.inst_data := inst_data 42 | IF_Stage.io.inst_valid := inst_valid 43 | inst_ack := IF_Stage.io.inst_ack 44 | 45 | val EX_Stage = Module(new CPU_EX(rv_width)) 46 | data_addr := EX_Stage.io.data_addr 47 | data_write_mem := EX_Stage.io.data_write_mem 48 | data_read_mem := EX_Stage.io.data_read_mem 49 | data_write_mmio := EX_Stage.io.data_write_mmio 50 | data_read_mmio := EX_Stage.io.data_read_mmio 51 | data_size := EX_Stage.io.data_size 52 | data_write_data := EX_Stage.io.data_write_data 53 | EX_Stage.io.data_req_ack := data_req_ack 54 | EX_Stage.io.data_read_data := data_read_data 55 | EX_Stage.io.data_read_valid := data_read_valid 56 | data_data_ack := EX_Stage.io.data_data_ack 57 | 58 | 59 | EX_Stage.io.fs_pc := IF_Stage.io.fs_pc 60 | EX_Stage.io.fs_inst := IF_Stage.io.fs_inst 61 | EX_Stage.io.fs_ex := IF_Stage.io.fs_ex 62 | EX_Stage.io.fs_excode := IF_Stage.io.fs_excode 63 | EX_Stage.io.fs_to_es_valid := IF_Stage.io.fs_to_es_valid 64 | EX_Stage.io.es_next_branch := IF_Stage.io.es_next_branch 65 | 66 | IF_Stage.io.inst_reload := EX_Stage.io.inst_reload 67 | IF_Stage.io.es_allowin := EX_Stage.io.es_allowin 68 | IF_Stage.io.br_valid := EX_Stage.io.br_valid 69 | IF_Stage.io.br_target := EX_Stage.io.br_target 70 | IF_Stage.io.ex_valid := EX_Stage.io.ex_valid 71 | IF_Stage.io.ex_target := EX_Stage.io.ex_target 72 | 73 | val branch_predicter = Module(new branch_pred) 74 | 75 | IF_Stage.io.next_branch := branch_predicter.io.IF_next_branch 76 | branch_predicter.io.EX_new_instr := EX_Stage.io.branch_new_instr 77 | branch_predicter.io.EX_br_taken := EX_Stage.io.branch_br_taken 78 | 79 | val CPU_Bridge = Module(new AXI_Bridge(64)) 80 | CPU_Bridge.io.clock := clock 81 | CPU_Bridge.io.reset := reset 82 | 83 | CPU_Bridge.io.inst_req := inst_req_valid & ~IF_Stage.io.inst_req_mmio 84 | CPU_Bridge.io.inst_wr := 0.U 85 | CPU_Bridge.io.inst_size := 2.U 86 | CPU_Bridge.io.inst_addr := inst_addr 87 | CPU_Bridge.io.inst_wdata := 0.U 88 | 89 | CPU_Bridge.io.data_req := data_write_mem | data_read_mem 90 | CPU_Bridge.io.data_wr := data_write_mem 91 | CPU_Bridge.io.data_size := data_size 92 | CPU_Bridge.io.data_addr := data_addr 93 | CPU_Bridge.io.data_wdata := data_write_data 94 | 95 | 96 | val MMIO_Bridge = Module(new AXI_Bridge(64)) 97 | 98 | MMIO_Bridge.io.clock := clock 99 | MMIO_Bridge.io.reset := reset 100 | 101 | MMIO_Bridge.io.inst_req := inst_req_valid & IF_Stage.io.inst_req_mmio // do not send any request with inst for now 102 | MMIO_Bridge.io.inst_wr := 0.U 103 | MMIO_Bridge.io.inst_size := 2.U 104 | MMIO_Bridge.io.inst_addr := inst_addr 105 | MMIO_Bridge.io.inst_wdata := 0.U 106 | inst_req_ack := (IF_Stage.io.inst_req_mmio & MMIO_Bridge.io.inst_addr_ok) | (~IF_Stage.io.inst_req_mmio & CPU_Bridge.io.inst_addr_ok) 107 | inst_valid := (IF_Stage.io.inst_req_mmio & MMIO_Bridge.io.inst_data_ok) | (~IF_Stage.io.inst_req_mmio & CPU_Bridge.io.inst_data_ok) 108 | 109 | MMIO_Bridge.io.data_req := data_write_mmio | data_read_mmio 110 | MMIO_Bridge.io.data_wr := data_write_mmio 111 | MMIO_Bridge.io.data_size := data_size 112 | MMIO_Bridge.io.data_addr := data_addr 113 | MMIO_Bridge.io.data_wdata := data_write_data 114 | 115 | when (EX_Stage.io.is_mmio === 1.U) { 116 | data_read_data := MMIO_Bridge.io.data_rdata 117 | } .otherwise { 118 | data_read_data := CPU_Bridge.io.data_rdata 119 | } 120 | 121 | when (IF_Stage.io.inst_req_mmio === 1.U) { 122 | inst_data := MMIO_Bridge.io.inst_rdata 123 | } .otherwise { 124 | inst_data := CPU_Bridge.io.inst_rdata 125 | } 126 | 127 | data_req_ack := (EX_Stage.io.is_mmio & MMIO_Bridge.io.data_addr_ok) | (~EX_Stage.io.is_mmio & CPU_Bridge.io.data_addr_ok) 128 | data_read_valid := (EX_Stage.io.is_mmio & MMIO_Bridge.io.data_data_ok) | (~EX_Stage.io.is_mmio & CPU_Bridge.io.data_data_ok) 129 | 130 | io.mem.awid := CPU_Bridge.io.awid 131 | io.mem.awaddr := CPU_Bridge.io.awaddr 132 | io.mem.awlen := CPU_Bridge.io.awlen 133 | io.mem.awsize := CPU_Bridge.io.awsize 134 | io.mem.awburst := CPU_Bridge.io.awburst 135 | io.mem.awlock := CPU_Bridge.io.awlock 136 | io.mem.awcache := CPU_Bridge.io.awcache 137 | io.mem.awprot := CPU_Bridge.io.awprot 138 | io.mem.awvalid := CPU_Bridge.io.awvalid 139 | io.mem.ruser := 0.U 140 | CPU_Bridge.io.awready := io.mem.awready 141 | io.mem.wdata := CPU_Bridge.io.wdata 142 | io.mem.wstrb := CPU_Bridge.io.wstrb 143 | io.mem.wlast := CPU_Bridge.io.wlast 144 | io.mem.wvalid := CPU_Bridge.io.wvalid 145 | CPU_Bridge.io.wready := io.mem.wready 146 | CPU_Bridge.io.bid := io.mem.bid 147 | CPU_Bridge.io.bresp := io.mem.bresp 148 | CPU_Bridge.io.bvalid := io.mem.bvalid 149 | io.mem.bready := CPU_Bridge.io.bready 150 | io.mem.buser := 0.U 151 | io.mem.arid := CPU_Bridge.io.arid 152 | io.mem.araddr := CPU_Bridge.io.araddr 153 | io.mem.arlen := CPU_Bridge.io.arlen 154 | io.mem.arsize := CPU_Bridge.io.arsize 155 | io.mem.arburst := CPU_Bridge.io.arburst 156 | io.mem.arlock := CPU_Bridge.io.arlock 157 | io.mem.arcache := CPU_Bridge.io.arcache 158 | io.mem.arprot := CPU_Bridge.io.arcache 159 | io.mem.arvalid := CPU_Bridge.io.arvalid 160 | CPU_Bridge.io.arready := io.mem.arready 161 | CPU_Bridge.io.rid := io.mem.rid 162 | CPU_Bridge.io.rdata := io.mem.rdata 163 | CPU_Bridge.io.rresp := io.mem.rresp 164 | CPU_Bridge.io.rlast := io.mem.rlast 165 | CPU_Bridge.io.rvalid := io.mem.rvalid 166 | io.mem.rready := CPU_Bridge.io.rready 167 | 168 | io.mmio.awaddr := MMIO_Bridge.io.awaddr 169 | io.mmio.awprot := MMIO_Bridge.io.awprot 170 | io.mmio.awvalid := MMIO_Bridge.io.awvalid 171 | MMIO_Bridge.io.awready := io.mmio.awready 172 | io.mmio.wdata := MMIO_Bridge.io.wdata 173 | io.mmio.wstrb := MMIO_Bridge.io.wstrb 174 | io.mmio.wvalid := MMIO_Bridge.io.wvalid 175 | MMIO_Bridge.io.wready := io.mmio.wready 176 | MMIO_Bridge.io.bresp := io.mmio.bresp 177 | MMIO_Bridge.io.bvalid := io.mmio.bvalid 178 | io.mmio.bready := MMIO_Bridge.io.bready 179 | io.mmio.araddr := MMIO_Bridge.io.araddr 180 | io.mmio.arprot := MMIO_Bridge.io.arcache 181 | io.mmio.arvalid := MMIO_Bridge.io.arvalid 182 | MMIO_Bridge.io.arready := io.mmio.arready 183 | MMIO_Bridge.io.rdata := io.mmio.rdata 184 | MMIO_Bridge.io.rresp := io.mmio.rresp 185 | MMIO_Bridge.io.rvalid := io.mmio.rvalid 186 | io.mmio.rready := MMIO_Bridge.io.rready 187 | 188 | } 189 | 190 | object CPU_Core_SoC extends App { 191 | (new ChiselStage).execute( 192 | args, 193 | Seq( 194 | ChiselGeneratorAnnotation(() => new CPU_Core_SoC()), 195 | RunFirrtlTransformAnnotation(new AddModulePrefix()), 196 | ModulePrefixAnnotation("chenguokai_") 197 | ) 198 | ) 199 | 200 | //chisel3.Driver.execute(args, () => new CPU_Core_SoC()) 201 | } -------------------------------------------------------------------------------- /src/main/scala/Xim/CPU_IF.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import chisel3._ 4 | 5 | 6 | class CPU_IF(val rv_width: Int = 64) extends Module { 7 | val io = IO(new Bundle { 8 | val inst_addr = Output(UInt(rv_width.W)) 9 | val inst_req_valid = Output(UInt(1.W)) 10 | val inst_req_mmio = Output(UInt(1.W)) 11 | val inst_req_ack = Input(UInt(1.W)) 12 | 13 | val inst_data = Input(UInt(rv_width.W)) 14 | val inst_valid = Input(UInt(1.W)) 15 | val inst_ack = Output(UInt(1.W)) 16 | 17 | val es_allowin = Input(UInt(1.W)) 18 | val inst_reload = Input(UInt(1.W)) 19 | // maybe we do not need to deal with reload in this pipeline 20 | val fs_to_es_valid = Output(UInt(1.W)) 21 | val fs_pc = Output(UInt(rv_width.W)) 22 | val fs_inst = Output(UInt(32.W)) 23 | val fs_ex = Output(UInt(1.W)) 24 | val fs_excode = Output(UInt(5.W)) // maybe should be longer? 25 | 26 | val br_valid = Input(UInt(1.W)) 27 | val br_target = Input(UInt(rv_width.W)) 28 | 29 | val ex_valid = Input(UInt(1.W)) 30 | val ex_target = Input(UInt(rv_width.W)) 31 | 32 | // from branch predicter 33 | val next_branch = Input(UInt(1.W)) 34 | 35 | // handled in es 36 | val es_next_branch = Output(UInt(1.W)) 37 | }) 38 | 39 | 40 | 41 | // unimplemented end 42 | 43 | val fs_valid = RegInit(0.U(1.W)) 44 | val fs_allowin = Wire(UInt(1.W)) 45 | val fs_ready_go = Wire(UInt(1.W)) 46 | 47 | val next_pc = Wire(UInt(rv_width.W)) 48 | val next_fs_ex = RegInit(0.U(1.W)) 49 | val next_pc_mmio = Wire(UInt(1.W)) 50 | val fs_ex = RegInit(0.U(1.W)) 51 | val fs_pc_r = RegInit((0x3ffffffcL).U(rv_width.W)) 52 | next_pc_mmio := (next_pc < 0x80000000L.U) 53 | io.inst_req_mmio := next_pc_mmio 54 | 55 | // some handy signals 56 | val addr_handshake = Wire(UInt(1.W)) 57 | val data_handshake = Wire(UInt(1.W)) 58 | val data_handshake_r = RegInit(0.U(1.W)) 59 | 60 | val inst_req_valid_r = RegInit(0.U(1.W)) 61 | val inst_ack_r = RegInit(0.U(1.W)) 62 | val fs_inst_r = Reg(UInt(32.W)) 63 | 64 | // for branch prediction 65 | val is_br = Wire(UInt(1.W)) 66 | val is_jmp = Wire(UInt(1.W)) 67 | val this_br_target = Wire(UInt(rv_width.W)) 68 | 69 | val next_branch = RegInit(0.U) 70 | 71 | // Instruction misaligned has excode 0 72 | io.fs_excode := excode_const.InstructionMisaligned // the only possible exception here 73 | when (next_pc(1, 0) === 0.U) { 74 | // aligned 75 | next_fs_ex := 0.U 76 | } .otherwise { 77 | next_fs_ex := 1.U 78 | } 79 | 80 | fs_allowin := 1.U 81 | // TODO: check valid condition in the future 82 | when (fs_ready_go === 1.U && io.es_allowin === 1.U) { 83 | fs_valid := 0.U 84 | } .otherwise { 85 | fs_valid := 1.U 86 | } 87 | 88 | io.fs_to_es_valid := (fs_valid === 1.U && (data_handshake | data_handshake_r) === 1.U) || io.fs_ex === 1.U 89 | 90 | addr_handshake := io.inst_req_valid === 1.U && io.inst_req_ack === 1.U 91 | data_handshake := io.inst_ack === 1.U && io.inst_valid === 1.U 92 | fs_ready_go := data_handshake | data_handshake_r | io.fs_ex 93 | // if we encounter an misaligned exception, we are ready to go 94 | 95 | io.fs_pc := fs_pc_r 96 | 97 | when (io.ex_valid === 1.U) { 98 | next_pc := io.ex_target 99 | } .elsewhen (io.br_valid === 1.U) { 100 | next_pc := io.br_target 101 | } .elsewhen (is_jmp === 1.U || (is_br === 1.U && next_branch === 1.U)) { 102 | next_pc := this_br_target 103 | } .otherwise { 104 | next_pc := fs_pc_r + 4.U; 105 | } 106 | 107 | io.inst_addr := next_pc 108 | 109 | when(fs_ready_go === 1.U && io.es_allowin === 1.U) { 110 | // TODO: check maybe the update should happen when we are able to move to the next stage 111 | fs_pc_r := next_pc 112 | fs_ex := next_fs_ex 113 | next_branch := io.next_branch 114 | } 115 | 116 | io.es_next_branch := next_branch 117 | io.fs_ex := fs_ex 118 | 119 | when(io.ex_valid === 1.U) { 120 | data_handshake_r := 0.U 121 | }.elsewhen(data_handshake === 1.U && io.es_allowin === 1.U) { 122 | data_handshake_r := 0.U 123 | }.elsewhen(data_handshake === 1.U && io.es_allowin === 0.U) { 124 | data_handshake_r := 1.U 125 | } 126 | 127 | val inst_req_valid_set = RegInit(0.U(1.W)) 128 | 129 | when (fs_ready_go === 1.U && io.es_allowin === 1.U && io.fs_ex === 0.U) { 130 | inst_req_valid_set := 0.U 131 | } .elsewhen (fs_valid === 1.U && inst_req_valid_set === 0.U) { 132 | inst_req_valid_set := 1.U 133 | } 134 | 135 | when (fs_valid === 1.U && inst_req_valid_set === 0.U) { 136 | inst_req_valid_r := 1.U; 137 | }.elsewhen(addr_handshake === 1.U) { 138 | inst_req_valid_r := 0.U 139 | } 140 | 141 | io.inst_req_valid := inst_req_valid_r // maybe we should consider some reload signals in the future 142 | 143 | io.inst_ack := 1.U // always acknowledge 144 | 145 | io.fs_inst := fs_inst_r 146 | 147 | val branch_target_gen = Module(new branch_target(rv_width)) 148 | 149 | branch_target_gen.io.IF_instr_valid := data_handshake 150 | branch_target_gen.io.IF_pc := fs_pc_r 151 | is_br := branch_target_gen.io.is_br 152 | is_jmp := branch_target_gen.io.is_jmp 153 | this_br_target := branch_target_gen.io.br_target 154 | 155 | when(data_handshake === 1.U && next_pc(2) === 1.U) { 156 | // update our inst data 157 | fs_inst_r := io.inst_data(rv_width - 1, rv_width / 2) 158 | branch_target_gen.io.IF_instr := io.inst_data(rv_width - 1, rv_width / 2) 159 | } .elsewhen(data_handshake === 1.U && next_pc(2) === 0.U) { 160 | fs_inst_r := io.inst_data(rv_width / 2 - 1, 0) 161 | branch_target_gen.io.IF_instr := io.inst_data(rv_width / 2 - 1, 0) 162 | } .otherwise { 163 | branch_target_gen.io.IF_instr := 0.U 164 | } 165 | } 166 | 167 | object CPU_IF extends App { 168 | chisel3.Driver.execute(args, () => new CPU_IF) 169 | } 170 | -------------------------------------------------------------------------------- /src/main/scala/Xim/Constants.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import chisel3._ 4 | 5 | trait CSRConstants { 6 | val MSTATUS = 0x300.U 7 | val MISA = 0x301.U 8 | val MEDELEG = 0x302.U 9 | val MIDELEG = 0x303.U 10 | val MIE = 0x304.U 11 | val MTVEC = 0x305.U 12 | val MSCRATCH = 0x340.U 13 | val MEPC = 0x341.U 14 | val MCAUSE = 0x342.U 15 | val MTVAL = 0x343.U 16 | val MIP = 0x344.U 17 | val MVENDORID = 0xf11.U 18 | val MARCHID = 0xf12.U 19 | val MIMPID = 0xf13.U 20 | val MHARTID = 0xf14.U 21 | 22 | // custom encoding 23 | val MTIME = 0x7c0.U 24 | val MTIMECMP = 0x7c2.U 25 | 26 | // Supervisor Mode CSRs 27 | // Trap Setup 28 | val SSTATUS = 0x100.U 29 | val SEDELEG = 0x102.U 30 | val SIDELEG = 0x103.U 31 | val SIE = 0x104.U 32 | val STVEC = 0x105.U 33 | val SCOUNTEREN = 0x106.U 34 | // Trap Handling 35 | val SSCRATCH = 0x140.U 36 | val SEPC = 0x141.U 37 | val SCAUSE = 0x142.U 38 | val STVAL = 0x143.U 39 | val SIP = 0x144.U 40 | // Protection and Translation 41 | // val SATP = 0x180.U 42 | } 43 | 44 | trait ExceptionConstants { 45 | // Currently we do not handle page fault related exceptions 46 | val MachineTimerInt = "h8000000000000007".U 47 | val SupervisorTimerInt = "h8000000000000005".U 48 | val UserTimerInt = "h8000000000000004".U 49 | // No external exceptions for now 50 | val InstructionMisaligned = 0x00000000.U 51 | val IllegalInstruction = 0x00000002.U 52 | val LoadAddrMisaligned = 0x00000004.U 53 | val StoreAddrMisaligned = 0x00000006.U 54 | val MEcall = 0x0000000b.U 55 | val SEcall = 0x00000009.U 56 | val UEcall = 0x00000008.U 57 | } 58 | 59 | trait PriviledgeLevelConstants { 60 | val User = 0.U 61 | val Supervisor = 1.U 62 | val Machine = 3.U 63 | } -------------------------------------------------------------------------------- /src/main/scala/Xim/SoC.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | /* This is a simple SoC with a fake UART 4 | * Designed to be able to run some local tests 5 | * */ 6 | 7 | import chisel3._ 8 | import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} 9 | import firrtl.stage.RunFirrtlTransformAnnotation 10 | 11 | 12 | 13 | class SoC(val rv_width: Int = 64) extends Module { 14 | val io = IO(new Bundle { 15 | val reg_wen = Output(UInt(1.W)) 16 | val reg_wdata = Output(UInt(rv_width.W)) 17 | val reg_waddr = Output(UInt(5.W)) 18 | val es_instr = Output(UInt(32.W)) 19 | val es_pc = Output(UInt(rv_width.W)) 20 | val es_reg_a0 = Output(UInt(rv_width.W)) 21 | }) 22 | 23 | 24 | val Core = Module(new CPU_Core(64)) 25 | 26 | io.reg_wen := Core.io.reg_wen 27 | io.reg_wdata := Core.io.reg_wdata 28 | io.reg_waddr := Core.io.reg_waddr 29 | io.es_pc := Core.io.es_pc 30 | io.es_instr := Core.io.es_instr 31 | io.es_reg_a0 := Core.io.es_reg_a0 32 | 33 | val RAM = Module(new AXI_ram) 34 | RAM.io.clock := clock 35 | RAM.io.reset := reset 36 | 37 | val MMIO = Module(new AXI_ram) 38 | MMIO.io.clock := clock 39 | MMIO.io.reset := reset 40 | 41 | RAM.io.awid := Core.io.axi_mem.awid 42 | RAM.io.awaddr := Core.io.axi_mem.awaddr 43 | RAM.io.awlen := Core.io.axi_mem.awlen 44 | RAM.io.awsize := Core.io.axi_mem.awsize 45 | RAM.io.awburst := Core.io.axi_mem.awburst 46 | RAM.io.awlock := Core.io.axi_mem.awlock 47 | RAM.io.awcache := Core.io.axi_mem.awcache 48 | RAM.io.awprot := Core.io.axi_mem.awprot 49 | RAM.io.awvalid := Core.io.axi_mem.awvalid 50 | Core.io.axi_mem.awready := RAM.io.awready 51 | Core.io.axi_mem.awqos := 0.U 52 | Core.io.axi_mem.awuser := 0.U 53 | RAM.io.wdata := Core.io.axi_mem.wdata 54 | RAM.io.wstrb := Core.io.axi_mem.wstrb 55 | RAM.io.wlast := Core.io.axi_mem.wlast 56 | RAM.io.wvalid := Core.io.axi_mem.wvalid 57 | Core.io.axi_mem.wready := RAM.io.wready 58 | Core.io.axi_mem.bid := RAM.io.bid 59 | Core.io.axi_mem.bresp := RAM.io.bresp 60 | Core.io.axi_mem.bvalid := RAM.io.bvalid 61 | RAM.io.bready := Core.io.axi_mem.bready 62 | RAM.io.arid := Core.io.axi_mem.arid 63 | RAM.io.araddr := Core.io.axi_mem.araddr 64 | RAM.io.arlen := Core.io.axi_mem.arlen 65 | RAM.io.arsize := Core.io.axi_mem.arsize 66 | RAM.io.arburst := Core.io.axi_mem.arburst 67 | RAM.io.arlock := Core.io.axi_mem.arlock 68 | RAM.io.arcache := Core.io.axi_mem.arcache 69 | RAM.io.arprot := Core.io.axi_mem.arcache 70 | RAM.io.arvalid := Core.io.axi_mem.arvalid 71 | Core.io.axi_mem.arready := RAM.io.arready 72 | Core.io.axi_mem.arqos := 0.U 73 | Core.io.axi_mem.aruser := 0.U 74 | Core.io.axi_mem.rid := RAM.io.rid 75 | Core.io.axi_mem.rdata := RAM.io.rdata 76 | Core.io.axi_mem.rresp := RAM.io.rresp 77 | Core.io.axi_mem.rlast := RAM.io.rlast 78 | Core.io.axi_mem.rvalid := RAM.io.rvalid 79 | RAM.io.rready := Core.io.axi_mem.rready 80 | // Core.io.axi_mem.ruser := 0.U 81 | 82 | MMIO.io.awid := Core.io.axi_mmio.awid 83 | MMIO.io.awaddr := Core.io.axi_mmio.awaddr 84 | MMIO.io.awlen := Core.io.axi_mmio.awlen 85 | MMIO.io.awsize := Core.io.axi_mmio.awsize 86 | MMIO.io.awburst := Core.io.axi_mmio.awburst 87 | MMIO.io.awlock := Core.io.axi_mmio.awlock 88 | MMIO.io.awcache := Core.io.axi_mmio.awcache 89 | MMIO.io.awprot := Core.io.axi_mmio.awprot 90 | MMIO.io.awvalid := Core.io.axi_mmio.awvalid 91 | Core.io.axi_mmio.awqos := 0.U 92 | Core.io.axi_mmio.awuser := 0.U 93 | Core.io.axi_mmio.awready := MMIO.io.awready 94 | MMIO.io.wdata := Core.io.axi_mmio.wdata 95 | MMIO.io.wstrb := Core.io.axi_mmio.wstrb 96 | MMIO.io.wlast := Core.io.axi_mmio.wlast 97 | MMIO.io.wvalid := Core.io.axi_mmio.wvalid 98 | Core.io.axi_mmio.wready := MMIO.io.wready 99 | Core.io.axi_mmio.bid := MMIO.io.bid 100 | Core.io.axi_mmio.bresp := MMIO.io.bresp 101 | Core.io.axi_mmio.bvalid := MMIO.io.bvalid 102 | MMIO.io.bready := Core.io.axi_mmio.bready 103 | MMIO.io.arid := Core.io.axi_mmio.arid 104 | MMIO.io.araddr := Core.io.axi_mmio.araddr 105 | MMIO.io.arlen := Core.io.axi_mmio.arlen 106 | MMIO.io.arsize := Core.io.axi_mmio.arsize 107 | MMIO.io.arburst := Core.io.axi_mmio.arburst 108 | MMIO.io.arlock := Core.io.axi_mmio.arlock 109 | MMIO.io.arcache := Core.io.axi_mmio.arcache 110 | MMIO.io.arprot := Core.io.axi_mmio.arcache 111 | MMIO.io.arvalid := Core.io.axi_mmio.arvalid 112 | Core.io.axi_mmio.arqos := 0.U 113 | Core.io.axi_mmio.aruser := 0.U 114 | Core.io.axi_mmio.arready := MMIO.io.arready 115 | Core.io.axi_mmio.rid := MMIO.io.rid 116 | Core.io.axi_mmio.rdata := MMIO.io.rdata 117 | Core.io.axi_mmio.rresp := MMIO.io.rresp 118 | Core.io.axi_mmio.rlast := MMIO.io.rlast 119 | Core.io.axi_mmio.rvalid := MMIO.io.rvalid 120 | MMIO.io.rready := Core.io.axi_mmio.rready 121 | 122 | 123 | val uart = Module(new AXI_fake_serial) 124 | uart.io.wdata := Core.io.axi_mem.wdata 125 | uart.io.wvalid := Core.io.axi_mem.wvalid 126 | uart.io.awaddr := Core.io.axi_mem.awaddr 127 | uart.io.awvalid := Core.io.axi_mem.awvalid 128 | 129 | // printf(p"SRAM-like: inst_addr = ${Core.io.inst_addr} inst_req = ${Core.io.inst_req}, inst_wr = ${Core.io.inst_wr} inst_addr_ok = ${Core.io.inst_addr_ok}\n") 130 | // printf(p"AXI RAM: araddr = ${Core.io.araddr} arready = ${Core.io.arready} arvalid = ${Core.io.arvalid} rready = ${Core.io.rready} rvalid = ${Core.io.rvalid} rdata = ${Core.io.rdata}\n") 131 | } 132 | 133 | object SoC extends App { 134 | (new ChiselStage).execute( 135 | args, 136 | Seq( 137 | ChiselGeneratorAnnotation(() => new SoC()), 138 | RunFirrtlTransformAnnotation(new AddModulePrefix()), 139 | ModulePrefixAnnotation("chenguokai_") 140 | ) 141 | ) 142 | 143 | //chisel3.Driver.execute(args, () => new CPU_Core_SoC()) 144 | } -------------------------------------------------------------------------------- /src/main/scala/Xim/alu.scala: -------------------------------------------------------------------------------- 1 | // See README.md for license details. 2 | 3 | package Xim 4 | 5 | import chisel3._ 6 | import chisel3.internal.firrtl.Width 7 | 8 | class MySlt(val rv_width: Int = 64) extends Bundle { 9 | val zero = UInt((rv_width - 1).W) 10 | val sig = UInt(1.W) 11 | } 12 | 13 | class MyLui extends Bundle { 14 | val upper = UInt(52.W) 15 | val zero = UInt((12).W) 16 | } 17 | 18 | 19 | /** 20 | * ALU module 21 | */ 22 | class ALU(val rv_width: Int = 64) extends Module { 23 | val io = IO(new Bundle { 24 | val alu_src1 = Input(UInt(rv_width.W)) 25 | val alu_src2 = Input(UInt(rv_width.W)) 26 | val alu_op = Input(UInt(14.W)) 27 | val alu_result = Output(UInt(rv_width.W)) 28 | val alu_overflow = Output(UInt(1.W)) 29 | }) 30 | 31 | 32 | val op_add = Wire(UInt(1.W)) 33 | val op_sub = Wire(UInt(1.W)) 34 | val op_slt = Wire(UInt(1.W)) 35 | val op_sltu = Wire(UInt(1.W)) 36 | val op_and = Wire(UInt(1.W)) 37 | val op_nor = Wire(UInt(1.W)) 38 | val op_or = Wire(UInt(1.W)) 39 | val op_xor = Wire(UInt(1.W)) 40 | val op_sll = Wire(UInt(1.W)) 41 | val op_srl = Wire(UInt(1.W)) 42 | val op_sra = Wire(UInt(1.W)) 43 | val op_lui = Wire(UInt(1.W)) 44 | val op_srl_w = Wire(UInt(1.W)) 45 | val op_sra_w = Wire(UInt(1.W)) 46 | 47 | op_add := io.alu_op(0) 48 | op_sub := io.alu_op(1) 49 | op_slt := io.alu_op(2) 50 | op_sltu := io.alu_op(3) 51 | op_and := io.alu_op(4) 52 | op_nor := io.alu_op(5) 53 | op_or := io.alu_op(6) 54 | op_xor := io.alu_op(7) 55 | op_sll := io.alu_op(8) 56 | op_srl := io.alu_op(9) 57 | op_sra := io.alu_op(10) 58 | op_lui := io.alu_op(11) 59 | op_srl_w := io.alu_op(12) 60 | op_sra_w := io.alu_op(13) 61 | 62 | val add_sub_result = Wire(UInt(rv_width.W)) 63 | val slt_result = Wire(new MySlt(rv_width)) 64 | val sltu_result = Wire(new MySlt(rv_width)) 65 | val and_result = Wire(UInt(rv_width.W)) 66 | val nor_result = Wire(UInt(rv_width.W)) 67 | val or_result = Wire(UInt(rv_width.W)) 68 | val xor_result = Wire(UInt(rv_width.W)) 69 | val lui_result = Wire(new MyLui) // will extend 70 | val lui_result_s = Wire(SInt(rv_width.W)) 71 | // Note that 6.W is not portable for non-64 bit 72 | val shift_off = Wire(UInt(6.W)) 73 | val sll_result = Wire(UInt(rv_width.W)) 74 | val srl_result = Wire(UInt(rv_width.W)) 75 | val sra_result = Wire(SInt(rv_width.W)) 76 | 77 | val srl_w_result = Wire(UInt(32.W)) 78 | val sra_w_result = Wire(SInt(32.W)) 79 | 80 | val adder_a = Wire(UInt(rv_width.W)) 81 | val adder_b = Wire(UInt(rv_width.W)) 82 | val adder_cin = Wire(UInt(1.W)) 83 | val adder_result = Wire(UInt(rv_width.W)) 84 | val adder_cout = Wire(UInt(rv_width.W)) 85 | val adder_ori_result = Wire(UInt((rv_width + 1).W)) 86 | 87 | adder_a := io.alu_src1 88 | 89 | when (op_sub === 1.U || op_sltu === 1.U) { 90 | adder_b := ~io.alu_src2 91 | } .otherwise { 92 | adder_b := io.alu_src2 93 | } 94 | 95 | when (op_sub === 1.U || op_sltu === 1.U) { 96 | adder_cin := 1.U 97 | } .otherwise { 98 | adder_cin := 0.U 99 | } 100 | 101 | adder_ori_result := adder_a +& adder_b +& adder_cin; 102 | 103 | adder_cout := adder_ori_result(rv_width) 104 | adder_result := adder_ori_result 105 | 106 | when (op_add === 1.U) { 107 | io.alu_overflow := (io.alu_src1((rv_width - 1).U) & io.alu_src2((rv_width - 1).U) & ~adder_result((rv_width - 1).U)) | 108 | (~io.alu_src1((rv_width - 1).U) & ~io.alu_src2((rv_width - 1).U) & adder_result((rv_width - 1).U)) 109 | }.elsewhen (op_sub === 1.U) { 110 | io.alu_overflow := (io.alu_src1((rv_width - 1).U) & ~io.alu_src2((rv_width - 1).U) & ~adder_result((rv_width - 1).U)) | 111 | (~io.alu_src1((rv_width - 1).U) & io.alu_src2((rv_width - 1).U) & adder_result((rv_width - 1).U)) 112 | } .otherwise { 113 | io.alu_overflow := 0.U; 114 | } 115 | 116 | add_sub_result := adder_result 117 | 118 | slt_result.zero := 0.U 119 | when (io.alu_src1.asSInt() < io.alu_src2.asSInt()) { 120 | slt_result.sig := 1.U 121 | } .otherwise { 122 | slt_result.sig := 0.U 123 | } 124 | 125 | 126 | sltu_result.zero := 0.U 127 | sltu_result.sig := ~adder_cout 128 | 129 | and_result := io.alu_src1 & io.alu_src2 130 | or_result := io.alu_src1 | io.alu_src2 131 | nor_result := ~or_result 132 | xor_result := io.alu_src1 ^ io.alu_src2 133 | 134 | // need testing here 135 | lui_result.upper := io.alu_src2((rv_width - 1), 12) 136 | lui_result.zero := 0.U 137 | lui_result_s := lui_result.asUInt().asSInt() 138 | 139 | shift_off := io.alu_src2 140 | sll_result := io.alu_src1 << shift_off 141 | srl_result := io.alu_src1 >> shift_off 142 | sra_result := io.alu_src1.asSInt >> shift_off 143 | 144 | srl_w_result := io.alu_src1(31, 0) >> shift_off 145 | sra_w_result := io.alu_src1(31, 0).asSInt >> shift_off 146 | 147 | when (op_add === 1.U || op_sub === 1.U) { 148 | io.alu_result := add_sub_result 149 | } .elsewhen (op_slt === 1.U) { 150 | io.alu_result := slt_result.asUInt 151 | } .elsewhen (op_sltu === 1.U) { 152 | io.alu_result := sltu_result.asUInt 153 | } .elsewhen (op_and === 1.U) { 154 | io.alu_result := and_result 155 | } .elsewhen (op_nor === 1.U) { 156 | io.alu_result := nor_result 157 | } .elsewhen (op_or === 1.U) { 158 | io.alu_result := or_result 159 | } .elsewhen (op_xor === 1.U) { 160 | io.alu_result := xor_result 161 | } .elsewhen (op_lui === 1.U) { 162 | io.alu_result := lui_result_s.asUInt 163 | } .elsewhen (op_sll === 1.U) { 164 | io.alu_result := sll_result 165 | } .elsewhen (op_srl === 1.U) { 166 | io.alu_result := srl_result 167 | } .elsewhen (op_sra === 1.U) { 168 | io.alu_result := sra_result.asUInt 169 | } .elsewhen (op_sra_w === 1.U) { 170 | io.alu_result := sra_w_result.asUInt 171 | } .elsewhen (op_srl_w === 1.U) { 172 | io.alu_result := srl_w_result.asUInt 173 | } .otherwise { 174 | io.alu_result := 0.U; 175 | } 176 | } 177 | 178 | 179 | object ALU extends App { 180 | chisel3.Driver.execute(args, () => new ALU(64)) 181 | } -------------------------------------------------------------------------------- /src/main/scala/Xim/branch_pred.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import chisel3._ 4 | 5 | class branch_pred extends Module { 6 | val io = IO(new Bundle{ 7 | // whether IF should fetch br target 8 | val IF_next_branch = Output(UInt(1.W)) 9 | // as the valid condition for EX_taken 10 | val EX_new_instr = Input(UInt(1.W)) 11 | // note that a taken of unconditional jmp is not taken into account 12 | // since that they will never cause an empty slot in pipeline 13 | val EX_br_taken = Input(UInt(1.W)) 14 | }) 15 | val pred_counter = RegInit(0.U(2.W)) 16 | when (io.EX_new_instr === 1.U && io.EX_br_taken === 1.U && pred_counter != 3.U) { 17 | // if the counter is not currently full and a new taken come in 18 | pred_counter := pred_counter + 1.U 19 | } .elsewhen (io.EX_new_instr === 1.U && io.EX_br_taken === 0.U) { 20 | // if the counter is not empty and a new not taken come in 21 | pred_counter := pred_counter - 1.U 22 | } 23 | io.IF_next_branch := (pred_counter > 1.U) 24 | } 25 | 26 | /* 27 | * This module is the helper module for IF to identify the branch instructions 28 | * Note that we do not identify any jmp reg instructions since we cannot fetch the branch target 29 | * */ 30 | 31 | class branch_target(val rv_width: Int = 64) extends Module { 32 | val io = IO(new Bundle{ 33 | val IF_instr = Input(UInt(32.W)) 34 | // refers to new data handshake 35 | val IF_instr_valid = Input(UInt(1.W)) 36 | val IF_pc = Input(UInt(rv_width.W)) 37 | val is_br = Output(UInt(1.W)) 38 | val is_jmp = Output(UInt(1.W)) 39 | val br_target = Output(UInt(rv_width.W)) 40 | }) 41 | // note that we handle jal beq bne blt bge bltu bgeu 42 | val opcode = Wire(UInt(7.W)) 43 | val opcode_d = Wire(UInt(128.W)) 44 | val funct3 = Wire(UInt(3.W)) 45 | val funct3_d = Wire(UInt(8.W)) 46 | val inst_jal = Wire(UInt(1.W)) 47 | val inst_beq = Wire(UInt(1.W)) 48 | val inst_bne = Wire(UInt(1.W)) 49 | val inst_blt = Wire(UInt(1.W)) 50 | val inst_bge = Wire(UInt(1.W)) 51 | val inst_bltu = Wire(UInt(1.W)) 52 | val inst_bgeu = Wire(UInt(1.W)) 53 | val inst_b = Wire(UInt(1.W)) 54 | val inst_j = Wire(UInt(1.W)) 55 | 56 | val instr_r = RegInit(0.U(32.W)) 57 | val pred_valid = Wire(UInt(1.W)) 58 | 59 | // able to provide a consistent signal for instr as soon as new instr comes 60 | val instr_consistent = Wire(UInt(32.W)) 61 | 62 | instr_consistent := instr_r 63 | 64 | when (io.IF_instr_valid === 1.U) { 65 | instr_r := io.IF_instr 66 | } 67 | 68 | opcode := instr_consistent(6, 0) 69 | funct3 := instr_consistent(14, 12) 70 | val opcode_decoder: decoder_7_128 = Module(new decoder_7_128) 71 | val funct3_decoder: decoder_3_8 = Module(new decoder_3_8) 72 | opcode_decoder.io.in := opcode 73 | opcode_d := opcode_decoder.io.out 74 | funct3_decoder.io.in := funct3 75 | funct3_d := funct3_decoder.io.out 76 | 77 | inst_jal := (opcode_d(0x6f) === 1.U) 78 | inst_beq := (opcode_d(0x63) === 1.U) && (funct3_d(0) === 1.U) 79 | inst_bne := (opcode_d(0x63) === 1.U) && (funct3_d(1) === 1.U) 80 | inst_blt := (opcode_d(0x63) === 1.U) && (funct3_d(4) === 1.U) 81 | inst_bge := (opcode_d(0x63) === 1.U) && (funct3_d(5) === 1.U) 82 | inst_bltu := (opcode_d(0x63) === 1.U) && (funct3_d(6) === 1.U) 83 | inst_bgeu := (opcode_d(0x63) === 1.U) && (funct3_d(7) === 1.U) 84 | 85 | 86 | inst_b := inst_beq | inst_bne | inst_blt | inst_bge | inst_bltu | inst_bgeu 87 | inst_j := inst_jal 88 | 89 | val jal_target = Wire(UInt(rv_width.W)) 90 | val branch_target = Wire(UInt(rv_width.W)) 91 | 92 | io.is_br := inst_jal | inst_beq | inst_bne | inst_blt | inst_bge | inst_bltu | inst_bgeu 93 | when (inst_jal === 1.U) { 94 | io.br_target := jal_target + io.IF_pc 95 | } .otherwise { 96 | io.br_target := branch_target + io.IF_pc 97 | } 98 | 99 | // jal instruction will always jump so ignore the counter 100 | pred_valid := inst_b === 1.U 101 | 102 | 103 | io.is_br := inst_b 104 | io.is_jmp := inst_j 105 | 106 | val B_imm_b = Wire(new B_imm_bundle) 107 | val J_imm_b = Wire(new J_imm_bundle) 108 | val B_imm = Wire(SInt(rv_width.W)) // sign extend 109 | val J_imm = Wire(SInt(rv_width.W)) // sign extend 110 | B_imm := (B_imm_b.asUInt).asSInt() 111 | J_imm := (J_imm_b.asUInt).asSInt() 112 | 113 | B_imm_b.inst_31 := instr_consistent(31) 114 | B_imm_b.inst_7 := instr_consistent(7) 115 | B_imm_b.inst_30_25 := instr_consistent(30, 25) 116 | B_imm_b.inst_11_8 := instr_consistent(11, 8) 117 | B_imm_b.zero := 0.U 118 | 119 | J_imm_b.inst_31 := instr_consistent(31) 120 | J_imm_b.inst_19_12 := instr_consistent(19, 12) 121 | J_imm_b.inst_20 := instr_consistent(20) 122 | J_imm_b.inst_30_25 := instr_consistent(30, 25) 123 | J_imm_b.inst_24_21 := instr_consistent(24, 21) 124 | J_imm_b.zero := 0.U 125 | 126 | jal_target := J_imm.asUInt() 127 | branch_target := B_imm.asUInt() 128 | 129 | } -------------------------------------------------------------------------------- /src/main/scala/Xim/commented.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | // Note that this file stores some reference code which is no longer used in actual code 4 | 5 | /* 6 | * when (inst_sw === 1.U) { 7 | io.data_wstrb := 0xf.U 8 | } .elsewhen (inst_sh === 1.U) { 9 | io.data_wstrb := 0x3.U 10 | } .elsewhen (inst_sb === 1.U) { 11 | io.data_wstrb := 0x1.U 12 | } .otherwise { 13 | io.data_wstrb := 0.U; 14 | } 15 | * */ 16 | 17 | /* 18 | reg_raddr.raddr1 := reg_raddr_1 19 | reg_raddr.raddr2 := reg_raddr_2 20 | */ 21 | 22 | /* 23 | csr_mstatus.SD := 0.U // hardwired to zero 24 | csr_mstatus.reserved := 0.U // hardwired to zero 25 | csr_mstatus.TSR := 0.U // hardwired to zero 26 | csr_mstatus.TW := 0.U // hardwired to zero 27 | csr_mstatus.TVM := 0.U // hardwired to zero 28 | csr_mstatus.MXR := 0.U // hardwired to zero 29 | csr_mstatus.SUM := 0.U // hardwired to zero 30 | csr_mstatus.MPRV := 0.U // hardwired to zero 31 | csr_mstatus.XS := 0.U // hardwired to zero 32 | csr_mstatus.FS := 0.U // hardwired to zero 33 | csr_mstatus.MPP := 0x3.U // always machine mode 34 | csr_mstatus.reserved_2 := 0.U // hardwired to zero 35 | csr_mstatus.SPP := 0.U // hardwired to zero 36 | 37 | csr_mstatus.MPIE := RegInit(0.U); 38 | csr_mstatus.MIE := RegInit(0.U); 39 | */ 40 | /* 41 | csr_mstatus.reserved_3 := 0.U // hardwired to zero 42 | csr_mstatus.SPIE := 0.U // hardwired to zero 43 | csr_mstatus.UPIE := 0.U // hardwired to zero 44 | csr_mstatus.reserved_4 := 0.U // hardwired to zero 45 | csr_mstatus.SIE := 0.U // hardwired to zero 46 | csr_mstatus.UIE := 0.U // hardwired to zero 47 | */ 48 | 49 | 50 | /* 51 | csr_mtvec.base := RegInit(0.U) 52 | csr_mtvec.mode := RegInit(0.U) 53 | */ 54 | 55 | 56 | /* 57 | csr_mip.reserved := 0.U // hardwired to zero 58 | csr_mip.reserved_2 := 0.U // hardwired to zero 59 | csr_mip.SEIP := 0.U // hardwired to zero 60 | csr_mip.UEIP := 0.U // hardwired to zero 61 | csr_mip.MTIP := 1.U // hardwired to one 62 | csr_mip.reserved_3 := 0.U // hardwired to zero 63 | csr_mip.STIP := 0.U // hardwired to zero 64 | csr_mip.UTIP := 0.U // hardwired to zero 65 | csr_mip.MSIP := 0.U // hardwired to zero 66 | csr_mip.reserved_4 := 0.U // hardwired to zero 67 | csr_mip.SSIP := 0.U // hardwired to zero 68 | csr_mip.USIP := 0.U // hardwired to zero 69 | 70 | csr_mip.MEIP := RegInit(0.U) 71 | */ 72 | 73 | 74 | /* 75 | csr_mie.reserved := 0.U // hardwired to zero 76 | csr_mie.reserved_2 := 0.U // hardwired to zero 77 | csr_mie.SEIE := 0.U // hardwired to zero 78 | csr_mie.UEIE := 0.U // hardwired to zero 79 | csr_mie.reserved_3 := 0.U // hardwired to zero 80 | csr_mie.STIE := 0.U // hardwired to zero 81 | csr_mie.UTIE := 0.U // hardwired to zero 82 | csr_mie.reserved_4 := 0.U // hardwired to zero 83 | csr_mie.SSIE := 0.U // hardwired to zero 84 | csr_mie.USIE := 0.U // hardwired to zero 85 | 86 | csr_mie.MSIE := RegInit(0.U) 87 | csr_mie.MTIE := RegInit(0.U) 88 | csr_mie.MEIE := RegInit(0.U) 89 | */ 90 | 91 | 92 | /* 93 | csr_mtime.zero := 0.U 94 | csr_mtime.value := RegInit(0.U) 95 | */ 96 | 97 | 98 | /* 99 | csr_mtimecmp.zero := 0.U 100 | csr_mtimecmp.value := RegInit(0.U) 101 | */ 102 | 103 | 104 | /* 105 | csr_mscratch.value := RegInit(0.U) 106 | */ 107 | 108 | 109 | /* 110 | csr_mepc.value := RegInit(0.U) 111 | */ 112 | 113 | /* 114 | // PTW_Bridge.io <> io.AXI part 115 | io.awid := PTW_Bridge.io.awid 116 | io.awaddr := PTW_Bridge.io.awaddr 117 | io.awlen := PTW_Bridge.io.awlen 118 | io.awsize := PTW_Bridge.io.awsize 119 | io.awburst := PTW_Bridge.io.awburst 120 | io.awlock := PTW_Bridge.io.awlock 121 | io.awcache := PTW_Bridge.io.awcache 122 | io.awprot := PTW_Bridge.io.awprot 123 | io.awvalid := PTW_Bridge.io.awvalid 124 | PTW_Bridge.io.awready := io.awready 125 | io.wdata := PTW_Bridge.io.wdata 126 | io.wstrb := PTW_Bridge.io.wstrb 127 | io.wlast := PTW_Bridge.io.wlast 128 | io.wvalid := PTW_Bridge.io.wvalid 129 | PTW_Bridge.io.wready := io.wready 130 | PTW_Bridge.io.bid := io.bid 131 | PTW_Bridge.io.bresp := io.bresp 132 | PTW_Bridge.io.bvalid := io.bvalid 133 | io.bready := PTW_Bridge.io.bready 134 | io.arid := PTW_Bridge.io.arid 135 | io.araddr := PTW_Bridge.io.araddr 136 | io.arlen := PTW_Bridge.io.arlen 137 | io.arsize := PTW_Bridge.io.arsize 138 | io.arburst := PTW_Bridge.io.arburst 139 | io.arlock := PTW_Bridge.io.arlock 140 | io.arcache := PTW_Bridge.io.arcache 141 | io.arprot := PTW_Bridge.io.arcache 142 | io.arvalid := PTW_Bridge.io.arvalid 143 | PTW_Bridge.io.arready := io.arready 144 | PTW_Bridge.io.rid := io.rid 145 | PTW_Bridge.io.rdata := io.rdata 146 | PTW_Bridge.io.rresp := io.rresp 147 | PTW_Bridge.io.rlast := io.rlast 148 | PTW_Bridge.io.rvalid := io.rvalid 149 | io.rready := PTW_Bridge.io.rready 150 | * */ 151 | 152 | /* 153 | // we do not use SRAM-like interface data channel 154 | PTW_Bridge.io.data_req := 0.U 155 | PTW_Bridge.io.data_wr := 0.U 156 | PTW_Bridge.io.data_size := 0.U 157 | PTW_Bridge.io.data_addr := 0.U 158 | PTW_Bridge.io.data_wdata := 0.U 159 | * */ -------------------------------------------------------------------------------- /src/main/scala/Xim/common.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import chisel3._ 4 | 5 | class I_imm_bundle extends Bundle { 6 | val inst_31 = UInt(1.W) 7 | val inst_30_25 = UInt(6.W) 8 | val inst_24_21 = UInt(4.W) 9 | val inst_20 = UInt(1.W) 10 | } 11 | 12 | class S_imm_bundle extends Bundle { 13 | val inst_31 = UInt(1.W) 14 | val inst_30_25 = UInt(6.W) 15 | val inst_11_8 = UInt(4.W) 16 | val inst_7 = UInt(1.W) 17 | } 18 | 19 | class B_imm_bundle extends Bundle { 20 | val inst_31 = UInt(1.W) 21 | val inst_7 = UInt(1.W) 22 | val inst_30_25 = UInt(6.W) 23 | val inst_11_8 = UInt(4.W) 24 | val zero = UInt(1.W) 25 | } 26 | 27 | class U_imm_bundle extends Bundle { 28 | val inst_31 = UInt(1.W) 29 | val inst_30_20 = UInt(11.W) 30 | val inst_19_12 = UInt(8.W) 31 | val zero = UInt(12.W) 32 | } 33 | 34 | class J_imm_bundle extends Bundle { 35 | val inst_31 = UInt(1.W) 36 | val inst_19_12 = UInt(8.W) 37 | val inst_20 = UInt(1.W) 38 | val inst_30_25 = UInt(6.W) 39 | val inst_24_21 = UInt(4.W) 40 | val zero = UInt(1.W) 41 | } 42 | 43 | class regfile_raddr extends Bundle { 44 | val raddr1 = UInt(5.W) 45 | val raddr2 = UInt(5.W) 46 | } 47 | 48 | class decoder_7_128 extends Module { 49 | val io = IO(new Bundle { 50 | val in = Input(UInt(7.W)) 51 | val out = Output(UInt(128.W)) 52 | }) 53 | val tmp = Wire(Vec(128, UInt(1.W))) 54 | for (i <- 0 until 128) { 55 | when (io.in === i.U) { 56 | tmp(i) := 1.U 57 | } .otherwise { 58 | tmp(i) := 0.U 59 | } 60 | } 61 | io.out := tmp.asUInt 62 | } 63 | 64 | class encoder(input_len: Int) extends Module { 65 | val io = IO(new Bundle{ 66 | val in = Input(input_len.asUInt()) 67 | val out = Output(UInt()) 68 | }) 69 | } 70 | 71 | class decoder_3_8 extends Module { 72 | val io = IO(new Bundle { 73 | val in = Input(UInt(3.W)) 74 | val out = Output(UInt(8.W)) 75 | }) 76 | val tmp = Wire(Vec(8, UInt(1.W))) 77 | for (i <- 0 until 8) { 78 | when (io.in === i.U) { 79 | tmp(i) := 1.U 80 | } .otherwise { 81 | tmp(i) := 0.U 82 | } 83 | } 84 | io.out := tmp.asUInt 85 | } 86 | 87 | class TLB_entry extends Bundle { 88 | val page_size = UInt(2.W) 89 | val VPN2 = UInt(9.W) 90 | val VPN1 = UInt(9.W) 91 | val VPN0 = UInt(9.W) 92 | val PPN2 = UInt(26.W) 93 | val PPN1 = UInt(9.W) 94 | val PPN0 = UInt(9.W) 95 | val D = UInt(1.W) 96 | val A = UInt(1.W) 97 | val G = UInt(1.W) 98 | val U = UInt(1.W) 99 | val X = UInt(1.W) 100 | val W = UInt(1.W) 101 | val R = UInt(1.W) 102 | val V = UInt(1.W) 103 | } 104 | 105 | class VAddr extends Bundle { 106 | val NotCare = UInt(25.W) 107 | val VPN2 = UInt(9.W) 108 | val VPN1 = UInt(9.W) 109 | val VPN0 = UInt(9.W) 110 | val offset = UInt(12.W) 111 | } 112 | 113 | class PAddr extends Bundle { 114 | val Zero = UInt(8.W) 115 | val PPN2 = UInt(26.W) 116 | val PPN1 = UInt(9.W) 117 | val PPN0 = UInt(9.W) 118 | val offset = UInt(12.W) 119 | } 120 | 121 | class PTE extends Bundle { 122 | val NotCare = UInt(10.W) 123 | val PPN2 = UInt(26.W) 124 | val PPN1 = UInt(9.W) 125 | val PPN0 = UInt(9.W) 126 | val RSW = UInt(2.W) 127 | val D = UInt(1.W) 128 | val A = UInt(1.W) 129 | val G = UInt(1.W) 130 | val U = UInt(1.W) 131 | val X = UInt(1.W) 132 | val W = UInt(1.W) 133 | val R = UInt(1.W) 134 | val V = UInt(1.W) 135 | } 136 | -------------------------------------------------------------------------------- /src/main/scala/Xim/csr.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import chisel3._ 4 | 5 | class CSR(val rv_width: Int = 64) extends Module { 6 | val io = IO(new Bundle { 7 | val es_ex = Input(UInt(1.W)) 8 | val es_ex_work = Output(UInt(1.W)) 9 | val es_new_instr = Input(UInt(1.W)) 10 | val es_excode = Input(UInt(rv_width.W)) 11 | val es_ex_pc = Input(UInt(rv_width.W)) 12 | val es_ex_addr = Input(UInt(rv_width.W)) 13 | val es_csr_wr = Input(UInt(1.W)) 14 | val es_csr_op = Input(UInt(1.W)) 15 | val es_csr_read_num = Input(UInt(12.W)) 16 | val es_csr_write_num = Input(UInt(12.W)) 17 | val es_csr_write_data = Input(UInt(rv_width.W)) 18 | val es_csr_read_data = Output(UInt(rv_width.W)) 19 | // timer interrupt 20 | val time_int = Output(UInt(1.W)) 21 | // trap entry 22 | val trap_entry = Output(UInt(rv_width.W)) 23 | // MEPC 24 | val mepc = Output(UInt(rv_width.W)) 25 | 26 | // exception related 27 | val mstatus_tsr = Output(UInt(1.W)) 28 | val mstatus_mpp = Output(UInt(2.W)) 29 | 30 | // Supervisor related 31 | val sstatus_spp = Output(UInt(1.W)) 32 | val sepc = Output(UInt(rv_width.W)) 33 | 34 | // for mtval 35 | val fault_addr = Input(UInt(rv_width.W)) 36 | val fault_instr = Input(UInt(32.W)) 37 | 38 | // mret 39 | val inst_mret = Input(UInt(1.W)) 40 | val mret_work = Output(UInt(1.W)) 41 | // sret 42 | val inst_sret = Input(UInt(1.W)) 43 | val sret_work = Output(UInt(1.W)) 44 | 45 | // priviledge level 46 | val priv_level = Input(UInt(2.W)) 47 | 48 | // reload signal, avoiding illegal state transition 49 | val inst_reload = Input(UInt(1.W)) 50 | 51 | // delegate trap 52 | val deleg_trap = Output(Bool()) 53 | 54 | // illegal csr operations 55 | val illegal_csr = Output(Bool()) 56 | }) 57 | // unimplemented signal: 58 | 59 | object csr_consts extends CSRConstants 60 | class misa extends Bundle { 61 | val MXL = UInt(2.W) 62 | // RV32: 1 RV64: 2 63 | val WLRL = UInt(36.W) 64 | val EXTEN = UInt(26.W) 65 | // I: bit 8 M: bit 12 66 | } 67 | 68 | class mvendorid extends Bundle { 69 | val zero = UInt(32.W) // always 32 bit 70 | } 71 | 72 | class marchid extends Bundle { 73 | val zero = UInt(rv_width.W) 74 | } 75 | 76 | class mimpid extends Bundle { 77 | val zero = UInt(rv_width.W) 78 | } 79 | 80 | class mhartid extends Bundle { 81 | val zero = UInt(rv_width.W) 82 | } 83 | 84 | class mstatus extends Bundle { 85 | val SD = UInt(1.W) // hardwired to zero 86 | val reserved = UInt(27.W) // hardwired to zero 87 | val SXL = UInt(2.W) // RV32:1 RV64:2 88 | val UXL = UInt(2.W) // RV32:1 RV64:2 89 | val reserved_1 = UInt(9.W) // hardwired to zero 90 | val TSR = UInt(1.W) 91 | val TW = UInt(1.W) // hardwired to zero 92 | val TVM = UInt(1.W) // hardwired to zero 93 | val MXR = UInt(1.W) // hardwired to zero 94 | val SUM = UInt(1.W) // hardwired to zero 95 | val MPRV = UInt(1.W) // hardwired to zero 96 | val XS = UInt(2.W) // hardwired to zero 97 | val FS = UInt(2.W) // hardwired to zero 98 | val MPP = UInt(2.W) // hardwired to 2'b11 99 | val reserved_2 = UInt(2.W) // hardwired to zero 100 | val SPP = UInt(1.W) // hardwired to zero 101 | val MPIE = UInt(1.W) 102 | val reserved_3 = UInt(1.W) // hardwired to zero 103 | val SPIE = UInt(1.W) // hardwired to zero 104 | val UPIE = UInt(1.W) // hardwired to zero 105 | val MIE = UInt(1.W) 106 | val reserved_4 = UInt(1.W) // hardwired to zero 107 | val SIE = UInt(1.W) // hardwired to zero 108 | val UIE = UInt(1.W) // hardwired to zero 109 | } 110 | 111 | class mtvec extends Bundle { 112 | val base = UInt((rv_width-2).W) 113 | val mode = UInt(2.W) 114 | } 115 | 116 | class mip extends Bundle { 117 | val reserved = UInt(52.W) 118 | val MEIP = UInt(1.W) 119 | val reserved_2 = UInt(1.W) 120 | val SEIP = UInt(1.W) 121 | val UEIP = UInt(1.W) 122 | val MTIP = UInt(1.W) 123 | val reserved_3 = UInt(1.W) 124 | val STIP = UInt(1.W) 125 | val UTIP = UInt(1.W) 126 | val MSIP = UInt(1.W) 127 | val reserved_4 = UInt(1.W) 128 | val SSIP = UInt(1.W) 129 | val USIP = UInt(1.W) 130 | } 131 | 132 | class mie extends Bundle { 133 | val reserved = UInt(52.W) 134 | val MEIE = UInt(1.W) 135 | val reserved_2 = UInt(1.W) 136 | val SEIE = UInt(1.W) 137 | val UEIE = UInt(1.W) 138 | val MTIE = UInt(1.W) 139 | val reserved_3 = UInt(1.W) 140 | val STIE = UInt(1.W) 141 | val UTIE = UInt(1.W) 142 | val MSIE = UInt(1.W) 143 | val reserved_4 = UInt(1.W) 144 | val SSIE = UInt(1.W) 145 | val USIE = UInt(1.W) 146 | } 147 | 148 | // wild chicken implementation here 149 | class mtime extends Bundle { 150 | val hi = UInt(32.W) 151 | val lo = UInt(32.W) 152 | } 153 | 154 | class mtimecmp extends Bundle { 155 | val hi = UInt(32.W) 156 | val lo = UInt(32.W) 157 | } 158 | 159 | class mscratch extends Bundle { 160 | val value = UInt(rv_width.W) 161 | } 162 | 163 | class mepc extends Bundle { 164 | val value = UInt(rv_width.W) 165 | } 166 | 167 | class mcause extends Bundle { 168 | val interrupt = UInt(1.W) 169 | val excode = UInt((rv_width - 1).W) 170 | } 171 | 172 | class mtval extends Bundle { 173 | val value = UInt(rv_width.W) 174 | } 175 | 176 | class medeleg extends Bundle { 177 | val value = UInt(rv_width.W) 178 | } 179 | 180 | class mideleg extends Bundle { 181 | val value = UInt(rv_width.W) 182 | } 183 | 184 | // Supervisor Mode CSRs 185 | class sstatus extends Bundle { 186 | val SD = UInt(1.W) 187 | val reserved = UInt(29.W) 188 | val UXL = UInt(2.W) 189 | val reserved_1 = UInt(12.W) 190 | val MXR = UInt(1.W) //currently not used because we do not support virtual memory 191 | val SUM = UInt(1.W) //currently not used because we do not support virtual memory 192 | val reserved_2 = UInt(1.W) 193 | val XS = UInt(2.W) 194 | val FS = UInt(2.W) 195 | val reserved_3 = UInt(4.W) 196 | val SPP = UInt(1.W) 197 | val reserved_4 = UInt(2.W) 198 | val SPIE = UInt(1.W) 199 | val UPIE = UInt(1.W) 200 | val reserved_5 = UInt(2.W) 201 | val SIE = UInt(1.W) 202 | val UIE = UInt(1.W) 203 | } 204 | 205 | class sepc extends Bundle { 206 | val value = UInt(rv_width.W) 207 | } 208 | 209 | class scause extends Bundle { 210 | val interrupt = UInt(1.W) 211 | val excode = UInt((rv_width - 1).W) 212 | } 213 | 214 | class stvec extends Bundle { 215 | val base = UInt((rv_width-2).W) 216 | val mode = UInt(2.W) 217 | } 218 | 219 | class sie extends Bundle { 220 | val reserved = UInt(54.W) 221 | val SEIE = UInt(1.W) 222 | val UEIE = UInt(1.W) 223 | val reserved_1 = UInt(2.W) 224 | val STIE = UInt(1.W) 225 | val UTIE = UInt(1.W) 226 | val reserved_2 = UInt(2.W) 227 | val SSIE = UInt(1.W) 228 | val USIE = UInt(1.W) 229 | } 230 | 231 | class sip extends Bundle { 232 | val reserved = UInt(54.W) 233 | val SEIP = UInt(1.W) 234 | val UEIP = UInt(1.W) 235 | val reserved_1 = UInt(2.W) 236 | val STIP = UInt(1.W) 237 | val UTIP = UInt(1.W) 238 | val reserved_2 = UInt(2.W) 239 | val SSIP = UInt(1.W) 240 | val USIP = UInt(1.W) 241 | } 242 | 243 | class stval extends Bundle { 244 | val value = UInt(rv_width.W) 245 | } 246 | 247 | class sscratch extends Bundle { 248 | val value = UInt(rv_width.W) 249 | } 250 | 251 | // val es_ex_set = RegInit(0.U(1.W)) 252 | val es_ex_once = Wire(UInt(1.W)) 253 | 254 | val mret_once = Wire(UInt(1.W)) 255 | val sret_once = Wire(UInt(1.W)) 256 | // val mret_set = RegInit(0.U(1.W)) 257 | 258 | val mtime_full = Wire(UInt(64.W)) 259 | val mtime_next_full = Wire(UInt(64.W)) 260 | val mtimecmp_full = Wire(UInt(64.W)) 261 | val time_int = Wire(UInt(1.W)) 262 | 263 | val csr_misa = Wire(new misa); 264 | val csr_mvendorid = Wire(new mvendorid) 265 | val csr_marchid = Wire(new marchid) 266 | val csr_mimpid = Wire(new mimpid) 267 | val csr_mhartid = Wire(new mhartid) 268 | // MSTATUS 269 | val reset_mstatus = WireInit(0.U.asTypeOf(new mstatus)) 270 | reset_mstatus.MPP := 0x3.U // Always at machine mode 271 | reset_mstatus.SXL := 0x2.U // RV64 272 | reset_mstatus.UXL := 0x2.U // RV64 273 | val csr_mstatus = RegInit(reset_mstatus) 274 | // MTVEC 275 | val reset_mtvec = WireInit(0.U.asTypeOf(new mtvec)) 276 | reset_mtvec.base := 0x10000000.U 277 | val csr_mtvec = RegInit(reset_mtvec) 278 | // MIP 279 | val reset_mip = WireInit(0.U.asTypeOf(new mip)) 280 | reset_mip.MTIP := 0.U 281 | val csr_mip = RegInit(reset_mip) 282 | // MIE 283 | val reset_mie = WireInit(0.U.asTypeOf(new mie)) 284 | val csr_mie = RegInit(reset_mie) 285 | // MTIME 286 | val reset_mtime = WireInit(0.U.asTypeOf(new mtime)) 287 | val csr_mtime = RegInit(reset_mtime) 288 | // MTIMECMP 289 | val reset_mtimecmp = WireInit(0.U).asTypeOf(new mtimecmp) 290 | reset_mtimecmp.hi := 0x7000000.U // avoid unexpected TIP 291 | val csr_mtimecmp = RegInit(reset_mtimecmp) 292 | // MSCRATCH 293 | val reset_mscratch = WireInit(0.U.asTypeOf(new mscratch)) 294 | val csr_mscratch = RegInit(reset_mscratch) 295 | // MEPC 296 | val reset_mepc = WireInit(0.U.asTypeOf(new mepc)) 297 | val csr_mepc = RegInit(reset_mepc) 298 | // MCAUSE 299 | val reset_mcause = WireInit(0.U.asTypeOf(new mcause)) 300 | val csr_mcause = RegInit(reset_mcause) 301 | // MTVAL 302 | val reset_mtval = WireInit(0.U.asTypeOf(new mtval)) 303 | val csr_mtval = RegInit(reset_mtval) 304 | // MEDELEG 305 | val reset_medeleg = WireInit(0.U.asTypeOf(new medeleg)) 306 | //reset_medeleg.value(11) := 0.U // m-mode ecall exception hardwired to zero 307 | val csr_medeleg = RegInit(reset_medeleg) 308 | // MIDELEG 309 | val reset_mideleg = WireInit(0.U.asTypeOf(new mideleg)) 310 | val csr_mideleg = RegInit(reset_mideleg) 311 | 312 | // SSTATUS 313 | val reset_sstatus = WireInit(0.U.asTypeOf(new sstatus)) 314 | //... 315 | val csr_sstatus = RegInit(reset_sstatus) 316 | // SEPC 317 | val reset_sepc = WireInit(0.U.asTypeOf(new sepc)) 318 | val csr_sepc = RegInit(reset_sepc) 319 | 320 | // STVEC 321 | val reset_stvec = WireInit(0.U.asTypeOf(new stvec)) 322 | reset_stvec.base := 0x10000000.U 323 | val csr_stvec = RegInit(reset_stvec) 324 | // SIP 325 | val reset_sip = WireInit(0.U.asTypeOf(new sip)) 326 | reset_sip.STIP := 0.U 327 | val csr_sip = RegInit(reset_sip) 328 | // SIE 329 | val reset_sie = WireInit(0.U.asTypeOf(new sie)) 330 | val csr_sie = RegInit(reset_sie) 331 | // SSCRATCH 332 | val reset_sscratch = WireInit(0.U.asTypeOf(new sscratch)) 333 | val csr_sscratch = RegInit(reset_sscratch) 334 | // SCAUSE 335 | val reset_scause = WireInit(0.U.asTypeOf(new scause)) 336 | val csr_scause = RegInit(reset_scause) 337 | // STVAL 338 | val reset_stval = WireInit(0.U.asTypeOf(new stval)) 339 | val csr_stval = RegInit(reset_stval) 340 | 341 | val isInterrupt = Wire(Bool()) 342 | val deleg = Wire(Bool()) 343 | val SupervisorTIDeleg = Wire(UInt(1.W)) 344 | val UserTIDeleg = Wire(UInt(1.W)) 345 | val machine_csr_op = Wire(Bool()) 346 | 347 | isInterrupt := io.es_excode(rv_width - 1) === 1.U 348 | deleg := ((isInterrupt && csr_mideleg.value(io.es_excode(3,0)) =/= 0.U) || (!isInterrupt && csr_medeleg.value(io.es_excode(3,0)) =/= 0.U)) && io.priv_level =/= priv_consts.Machine 349 | io.deleg_trap := deleg 350 | SupervisorTIDeleg := csr_mideleg.value(5) 351 | UserTIDeleg := csr_mideleg.value(4) 352 | 353 | when (io.es_new_instr === 1.U && io.es_ex === 1.U) { 354 | es_ex_once := 1.U 355 | } .otherwise { 356 | es_ex_once := 0.U 357 | } 358 | 359 | when (io.es_new_instr === 1.U && io.inst_mret === 1.U && io.inst_reload === 0.U) { 360 | mret_once := 1.U 361 | } .otherwise { 362 | mret_once := 0.U 363 | } 364 | 365 | when (io.es_new_instr === 1.U && io.inst_sret === 1.U && io.inst_reload === 0.U) { 366 | sret_once := 1.U 367 | } .otherwise { 368 | sret_once := 0.U 369 | } 370 | 371 | csr_misa.MXL := 2.U // RV64 372 | csr_misa.WLRL := 0.U // reserved 373 | csr_misa.EXTEN := 0x100.U // RV I 374 | 375 | csr_mvendorid.zero := 0.U // reserverd 376 | 377 | csr_marchid.zero := 0.U // reserved 378 | 379 | csr_mimpid.zero := 0.U 380 | 381 | csr_mhartid.zero := 0.U 382 | 383 | io.es_ex_work := es_ex_once 384 | io.mret_work := mret_once 385 | io.sret_work := sret_once 386 | 387 | // timer interrupt 388 | when (mtime_full === mtimecmp_full) { 389 | when (io.priv_level === priv_consts.Machine) { 390 | csr_mip.MTIP := 1.U 391 | } .elsewhen (io.priv_level === priv_consts.Supervisor) { 392 | when (SupervisorTIDeleg === 1.U) { 393 | csr_sip.STIP := 1.U 394 | } .otherwise { 395 | csr_mip.MTIP := 1.U 396 | } 397 | } .otherwise { 398 | when (UserTIDeleg === 1.U) { 399 | csr_sip.STIP := 1.U 400 | } .otherwise { 401 | csr_mip.MTIP := 1.U 402 | } 403 | } 404 | } 405 | 406 | when (csr_mip.MTIP === 1.U && csr_mstatus.MIE === 1.U && csr_mie.MTIE === 1.U) { 407 | time_int := 1.U 408 | } .elsewhen (csr_sip.STIP === 1.U && csr_sstatus.SIE === 1.U && csr_sie.STIE === 1.U) { 409 | time_int := 1.U 410 | } .otherwise { 411 | time_int := 0.U 412 | } 413 | 414 | // MSTATUS 415 | when (es_ex_once === 1.U && !deleg) { 416 | csr_mstatus.MPIE := csr_mstatus.MIE 417 | } .elsewhen (mret_once === 1.U) { 418 | csr_mstatus.MPIE := 1.U // according to the SPEC 419 | } .elsewhen (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.MSTATUS) { 420 | csr_mstatus.MPIE := io.es_csr_write_data(7) 421 | } 422 | 423 | when (es_ex_once === 1.U && !deleg) { 424 | csr_mstatus.MIE := 0.U 425 | } .elsewhen (mret_once === 1.U) { 426 | csr_mstatus.MIE := csr_mstatus.MPIE 427 | } .elsewhen (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.MSTATUS) { 428 | csr_mstatus.MIE := io.es_csr_write_data(3) 429 | } 430 | 431 | when (es_ex_once === 1.U && !deleg) { 432 | csr_mstatus.MPP := io.priv_level 433 | } .elsewhen (mret_once === 1.U) { 434 | csr_mstatus.MPP := priv_consts.User // by spec 435 | } .elsewhen (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.MSTATUS) { 436 | csr_mstatus.MPP := io.es_csr_write_data(12,11) 437 | } 438 | 439 | when (es_ex_once === 1.U && deleg) { 440 | csr_mstatus.SPP := io.priv_level 441 | csr_mstatus.SPIE := csr_mstatus.SIE 442 | csr_mstatus.SIE := 0.U 443 | } .elsewhen (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.MSTATUS) { 444 | csr_mstatus.SPP := io.es_csr_write_data(8) 445 | csr_mstatus.SPIE := io.es_csr_write_data(5) 446 | csr_mstatus.SIE := io.es_csr_write_data(1) 447 | } 448 | 449 | //io.mstatus_mie := csr_mstatus.MIE 450 | io.mstatus_tsr := csr_mstatus.TSR 451 | io.mstatus_mpp := csr_mstatus.MPP 452 | io.sstatus_spp := csr_sstatus.SPP 453 | 454 | // MTVEC 455 | when (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.MTVEC) { 456 | csr_mtvec.base := io.es_csr_write_data(rv_width - 1, 2) 457 | // csr_mtvec.mode := io.es_csr_write_data(1,0) 458 | // DIRECT Mode only 459 | } 460 | 461 | when (deleg) { 462 | io.trap_entry := csr_stvec.asUInt() 463 | } .otherwise { 464 | io.trap_entry := csr_mtvec.asUInt() 465 | } 466 | 467 | // MIP 468 | // TODO: revise updating condition of MIP and MIE 469 | when (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.MIP) { 470 | // TODO: should be read only here 471 | csr_mip.MEIP := io.es_csr_write_data(11) 472 | } 473 | 474 | when (io.es_csr_wr === 1.U && (io.es_csr_write_num === csr_consts.MTIME || 475 | io.es_csr_write_num === csr_consts.MTIMECMP )) { 476 | csr_mip.MTIP := 0.U 477 | } 478 | 479 | //io.mip := csr_mip.asUInt() 480 | 481 | // MIE 482 | when (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.MIE) { 483 | csr_mie.MEIE := io.es_csr_write_data(11) 484 | csr_mie.MTIE := io.es_csr_write_data(7) 485 | csr_mie.MSIE := io.es_csr_write_data(3) 486 | } 487 | //io.mie := csr_mie.asUInt() 488 | 489 | // MTIME 490 | // Note that mtime and mtimecmp is memory-mapped, be careful when treating this 491 | // TODO: memory mapped IO here and for mtimecmp 492 | io.time_int := time_int 493 | 494 | mtime_next_full := csr_mtime.asUInt() + 1.U 495 | mtime_full := csr_mtime.asUInt() 496 | mtimecmp_full := csr_mtimecmp.asUInt() 497 | 498 | val self_counter = RegInit(0.U(3.W)) // advance every eight cycles 499 | 500 | self_counter := self_counter + 1.U 501 | 502 | 503 | when (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.MTIME) { 504 | csr_mtime.lo := io.es_csr_write_data(31, 0) 505 | csr_mtime.hi := io.es_csr_write_data(63, 32) 506 | } .elsewhen (self_counter === 7.U) { 507 | csr_mtime.lo := mtime_next_full(31, 0) 508 | csr_mtime.hi := mtime_next_full(63, 32) 509 | } 510 | 511 | // MTIMECMP 512 | // TODO: memory mapped IO 513 | when (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.MTIMECMP) { 514 | csr_mtimecmp.lo := io.es_csr_write_data(31, 0) 515 | csr_mtimecmp.hi := io.es_csr_write_data(63, 32) 516 | } 517 | 518 | 519 | // MSCRATCH 520 | when (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.MSCRATCH) { 521 | csr_mscratch.value := io.es_csr_write_data 522 | } 523 | 524 | // MEPC 525 | when (es_ex_once === 1.U && !deleg) { 526 | csr_mepc.value := io.es_ex_pc 527 | } .elsewhen (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.MEPC) { 528 | csr_mepc.value := io.es_csr_write_data 529 | } 530 | 531 | io.mepc := csr_mepc.asUInt() 532 | io.sepc := csr_sepc.asUInt() 533 | 534 | // MCAUSE 535 | // excode is generated in pipeline 536 | when (es_ex_once === 1.U && !deleg) { 537 | csr_mcause.excode := io.es_excode(rv_width - 2, 0) 538 | csr_mcause.interrupt := io.es_excode(rv_width - 1) 539 | } .elsewhen (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.MCAUSE) { 540 | csr_mcause.interrupt := io.es_csr_write_data(rv_width - 1) 541 | csr_mcause.excode := io.es_csr_write_data(rv_width - 2, 0) 542 | } 543 | 544 | // MTVAL 545 | csr_mtval.value := RegInit(0.U) 546 | when (es_ex_once === 1.U && io.es_excode === excode_const.IllegalInstruction && !deleg) { 547 | csr_mtval.value := io.fault_instr 548 | } .elsewhen (es_ex_once === 1.U && (io.es_excode === excode_const.StoreAddrMisaligned || io.es_excode === excode_const.LoadAddrMisaligned || io.es_excode === excode_const.InstructionMisaligned) && !deleg) { 549 | csr_mtval.value := io.fault_addr 550 | } .elsewhen (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.MTVAL) { 551 | csr_mtval.value := io.es_csr_write_data 552 | } 553 | 554 | // MIDELEG 555 | when (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.MIDELEG) { 556 | csr_mideleg.value := io.es_csr_write_data 557 | } 558 | 559 | // MEDELEG 560 | when (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.MEDELEG) { 561 | csr_medeleg.value := io.es_csr_write_data 562 | } 563 | 564 | // SSTATUS 565 | when (es_ex_once === 1.U && deleg) { 566 | csr_sstatus.SPIE := csr_sstatus.SIE 567 | } .elsewhen (sret_once === 1.U) { 568 | csr_sstatus.SPIE := 1.U // according to the SPEC 569 | } .elsewhen (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.SSTATUS) { 570 | csr_sstatus.SPIE := io.es_csr_write_data(5) 571 | } 572 | 573 | when (es_ex_once === 1.U && deleg) { 574 | csr_sstatus.SIE := 0.U 575 | } .elsewhen (sret_once === 1.U) { 576 | csr_sstatus.SIE := csr_sstatus.SPIE 577 | } .elsewhen (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.SSTATUS) { 578 | csr_sstatus.SIE := io.es_csr_write_data(1) 579 | } 580 | 581 | when (es_ex_once === 1.U && deleg) { 582 | csr_sstatus.SPP := io.priv_level 583 | } .elsewhen (sret_once === 1.U) { 584 | csr_sstatus.SPP := 0.U // User, by spec 585 | } .elsewhen (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.SSTATUS) { 586 | csr_sstatus.SPP := io.es_csr_write_data(8) 587 | } 588 | 589 | // SEPC 590 | when (es_ex_once === 1.U && deleg) { 591 | csr_sepc.value := io.es_ex_pc 592 | } .elsewhen (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.SEPC) { 593 | csr_sepc.value := io.es_csr_write_data 594 | } 595 | 596 | // STVEC 597 | when (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.STVEC) { 598 | csr_stvec.base := io.es_csr_write_data(rv_width - 1, 2) 599 | // csr_mtvec.mode := io.es_csr_write_data(1,0) 600 | // DIRECT Mode only 601 | } 602 | 603 | // SIP 604 | when (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.SIP) { 605 | csr_sip.SEIP := io.es_csr_write_data(9) 606 | } 607 | 608 | when (io.es_csr_wr === 1.U && (io.es_csr_write_num === csr_consts.MTIME || 609 | io.es_csr_write_num === csr_consts.MTIMECMP )) { 610 | csr_sip.STIP := 0.U 611 | } 612 | 613 | // SIE 614 | when (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.SIE) { 615 | csr_sie.SEIE := io.es_csr_write_data(9) 616 | csr_sie.STIE := io.es_csr_write_data(5) 617 | csr_sie.SSIE := io.es_csr_write_data(1) 618 | } 619 | 620 | // SSCRATCH 621 | when (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.SSCRATCH) { 622 | csr_sscratch.value := io.es_csr_write_data 623 | } 624 | 625 | // SCAUSE 626 | // excode is generated in pipeline 627 | when (es_ex_once === 1.U && deleg) { 628 | csr_scause.excode := io.es_excode(rv_width - 2, 0) 629 | csr_scause.interrupt := io.es_excode(rv_width - 1) 630 | } .elsewhen (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.SCAUSE) { 631 | csr_scause.interrupt := io.es_csr_write_data(rv_width - 1) 632 | csr_scause.excode := io.es_csr_write_data(rv_width - 2, 0) 633 | } 634 | 635 | // STVAL 636 | csr_stval.value := RegInit(0.U) 637 | when (es_ex_once === 1.U && io.es_excode === excode_const.IllegalInstruction && deleg) { 638 | csr_stval.value := io.fault_instr 639 | } .elsewhen (es_ex_once === 1.U && (io.es_excode === excode_const.StoreAddrMisaligned || io.es_excode === excode_const.LoadAddrMisaligned || io.es_excode === excode_const.InstructionMisaligned) && deleg) { 640 | csr_stval.value := io.fault_addr 641 | } .elsewhen (io.es_csr_wr === 1.U && io.es_csr_write_num === csr_consts.STVAL) { 642 | csr_stval.value := io.es_csr_write_data 643 | } 644 | 645 | // READ Data path 646 | 647 | when (io.es_csr_read_num === csr_consts.MSTATUS) { 648 | io.es_csr_read_data := csr_mstatus.asUInt() 649 | machine_csr_op := true.B 650 | } .elsewhen(io.es_csr_read_num === csr_consts.MISA) { 651 | io.es_csr_read_data := csr_misa.asUInt() 652 | machine_csr_op := true.B 653 | } .elsewhen (io.es_csr_read_num === csr_consts.MVENDORID) { 654 | io.es_csr_read_data := csr_mvendorid.asUInt() 655 | machine_csr_op := true.B 656 | } .elsewhen (io.es_csr_read_num === csr_consts.MARCHID) { 657 | io.es_csr_read_data := csr_marchid.asUInt() 658 | machine_csr_op := true.B 659 | } .elsewhen (io.es_csr_read_num === csr_consts.MIMPID) { 660 | io.es_csr_read_data := csr_mimpid.asUInt() 661 | machine_csr_op := true.B 662 | } .elsewhen (io.es_csr_read_num === csr_consts.MHARTID) { 663 | io.es_csr_read_data := csr_mhartid.asUInt() 664 | machine_csr_op := true.B 665 | } .elsewhen (io.es_csr_read_num === csr_consts.MTVEC) { 666 | io.es_csr_read_data := csr_mtvec.asUInt() 667 | machine_csr_op := true.B 668 | } .elsewhen (io.es_csr_read_num === csr_consts.MIP) { 669 | io.es_csr_read_data := csr_mip.asUInt() 670 | machine_csr_op := true.B 671 | } .elsewhen (io.es_csr_read_num === csr_consts.MIE) { 672 | io.es_csr_read_data := csr_mie.asUInt() 673 | machine_csr_op := true.B 674 | } .elsewhen (io.es_csr_read_num === csr_consts.MSCRATCH) { 675 | io.es_csr_read_data := csr_mscratch.asUInt() 676 | machine_csr_op := true.B 677 | } .elsewhen (io.es_csr_read_num === csr_consts.MEPC) { 678 | io.es_csr_read_data := csr_mepc.asUInt() 679 | machine_csr_op := true.B 680 | } .elsewhen (io.es_csr_read_num === csr_consts.MCAUSE) { 681 | io.es_csr_read_data := csr_mcause.asUInt() 682 | machine_csr_op := true.B 683 | } .elsewhen (io.es_csr_read_num === csr_consts.MTVAL) { 684 | io.es_csr_read_data := csr_mtval.asUInt() 685 | machine_csr_op := true.B 686 | } .elsewhen (io.es_csr_read_num === csr_consts.MIDELEG) { 687 | io.es_csr_read_data := csr_mideleg.asUInt() 688 | machine_csr_op := true.B 689 | } .elsewhen (io.es_csr_read_num === csr_consts.MEDELEG) { 690 | io.es_csr_read_data := csr_medeleg.asUInt() 691 | machine_csr_op := true.B 692 | } .elsewhen (io.es_csr_read_num === csr_consts.MTIMECMP) { 693 | io.es_csr_read_data := csr_mtimecmp.asUInt() 694 | machine_csr_op := false.B 695 | } .elsewhen (io.es_csr_read_num === csr_consts.MTIME) { 696 | io.es_csr_read_data := csr_mtime.asUInt() 697 | machine_csr_op := false.B 698 | } .elsewhen (io.es_csr_read_num === csr_consts.SSTATUS) { 699 | io.es_csr_read_data := csr_sstatus.asUInt() 700 | machine_csr_op := false.B 701 | } .elsewhen (io.es_csr_read_num === csr_consts.STVEC) { 702 | io.es_csr_read_data := csr_stvec.asUInt() 703 | machine_csr_op := false.B 704 | } .elsewhen (io.es_csr_read_num === csr_consts.SEPC) { 705 | io.es_csr_read_data := csr_sepc.asUInt() 706 | machine_csr_op := false.B 707 | } .elsewhen (io.es_csr_read_num === csr_consts.SIP) { 708 | io.es_csr_read_data := csr_sip.asUInt() 709 | machine_csr_op := false.B 710 | } .elsewhen (io.es_csr_read_num === csr_consts.SIE) { 711 | io.es_csr_read_data := csr_sie.asUInt() 712 | machine_csr_op := false.B 713 | } .elsewhen (io.es_csr_read_num === csr_consts.SSCRATCH) { 714 | io.es_csr_read_data := csr_sscratch.asUInt() 715 | machine_csr_op := false.B 716 | } .elsewhen (io.es_csr_read_num === csr_consts.SCAUSE) { 717 | io.es_csr_read_data := csr_scause.asUInt() 718 | machine_csr_op := false.B 719 | } .elsewhen (io.es_csr_read_num === csr_consts.STVAL) { 720 | io.es_csr_read_data := csr_stval.asUInt() 721 | machine_csr_op := false.B 722 | } .otherwise { 723 | // WARNING: TEST ONLY 724 | io.es_csr_read_data := csr_mtime.asUInt() 725 | machine_csr_op := false.B 726 | } 727 | 728 | when (io.priv_level =/= priv_consts.Machine && io.es_csr_op === 1.U && machine_csr_op) { 729 | io.illegal_csr := true.B 730 | } .otherwise { 731 | io.illegal_csr := false.B 732 | } 733 | } 734 | 735 | object CSR extends App { 736 | chisel3.Driver.execute(args, () => new CSR) 737 | } 738 | 739 | class CSRSignal(val rv_width: Int = 64) extends Module { 740 | val io = IO(new Bundle { 741 | val mepc = Output(UInt(rv_width.W)) 742 | val sepc = Output(UInt(rv_width.W)) 743 | 744 | val es_new_instr = Input(UInt(1.W)) 745 | val es_ex = Input(UInt(1.W)) 746 | val es_ex_work = Output(UInt(1.W)) 747 | val es_excode = Input(UInt(rv_width.W)) 748 | val es_pc = Input(UInt(rv_width.W)) 749 | val es_instr = Input(UInt(32.W)) 750 | val es_csr = Input(UInt(1.W)) 751 | 752 | val inst_reserved = Input(UInt(1.W)) 753 | val inst_reload_r = Input(UInt(1.W)) 754 | val inst_mret = Input(UInt(1.W)) 755 | val inst_sret = Input(UInt(1.W)) 756 | val mret_work = Output(UInt(1.W)) 757 | val sret_work = Output(UInt(1.W)) 758 | val data_addr = Input(UInt(rv_width.W)) 759 | 760 | val Csr_num = Input(UInt(12.W)) 761 | val csr_read_data = Output(UInt(rv_width.W)) 762 | val csr_write_data = Input(UInt(rv_width.W)) 763 | val trap_entry = Output(UInt(rv_width.W)) 764 | 765 | val timer_int = Output(UInt(1.W)) 766 | val priv_level = Input(UInt(2.W)) 767 | 768 | val mstatus_tsr = Output(UInt(1.W)) 769 | val mstatus_mpp = Output(UInt(2.W)) 770 | val sstatus_spp = Output(UInt(1.W)) 771 | 772 | val deleg_trap = Output(Bool()) 773 | 774 | val illegal_csr = Output(Bool()) 775 | }) 776 | 777 | val CSR_module = Module(new CSR) 778 | val CSR_ex = Wire(UInt(1.W)) 779 | val CSR_excode = Wire(UInt(rv_width.W)) 780 | val CSR_epc = Wire(UInt(rv_width.W)) 781 | val CSR_badaddr = Wire(UInt(rv_width.W)) 782 | val CSR_write = Wire(UInt(1.W)) 783 | val CSR_read_num = Wire(UInt(12.W)) 784 | val CSR_write_num = Wire(UInt(12.W)) 785 | val CSR_fault_addr = Wire(UInt(rv_width.W)) 786 | val CSR_fault_instr = Wire(UInt(rv_width.W)) 787 | val CSR_op = Wire(UInt(1.W)) 788 | 789 | CSR_ex := io.es_ex 790 | CSR_excode := io.es_excode 791 | CSR_epc := io.es_pc 792 | 793 | CSR_module.io.es_ex := CSR_ex 794 | CSR_module.io.es_new_instr := io.es_new_instr // this is high only when new instr finally come in 795 | CSR_module.io.es_excode := CSR_excode 796 | CSR_module.io.es_ex_pc := CSR_epc 797 | CSR_module.io.es_ex_addr := CSR_badaddr 798 | CSR_module.io.es_csr_wr := CSR_write 799 | CSR_module.io.es_csr_op := CSR_op 800 | CSR_module.io.es_csr_read_num := CSR_read_num 801 | CSR_module.io.es_csr_write_num := CSR_write_num 802 | CSR_module.io.es_csr_write_data := io.csr_write_data 803 | CSR_module.io.fault_addr := CSR_fault_addr 804 | CSR_module.io.fault_instr := CSR_fault_instr 805 | CSR_module.io.inst_mret := io.inst_mret 806 | CSR_module.io.inst_sret := io.inst_sret 807 | CSR_module.io.priv_level := io.priv_level 808 | CSR_module.io.inst_reload := io.inst_reload_r 809 | io.csr_read_data := CSR_module.io.es_csr_read_data 810 | io.trap_entry := CSR_module.io.trap_entry 811 | io.mstatus_tsr := CSR_module.io.mstatus_tsr 812 | io.mstatus_mpp := CSR_module.io.mstatus_mpp 813 | io.sstatus_spp := CSR_module.io.sstatus_spp 814 | io.mepc := CSR_module.io.mepc 815 | io.sepc := CSR_module.io.sepc 816 | io.timer_int := CSR_module.io.time_int 817 | io.deleg_trap := CSR_module.io.deleg_trap 818 | io.illegal_csr := CSR_module.io.illegal_csr 819 | io.es_ex_work := CSR_module.io.es_ex_work 820 | io.mret_work := CSR_module.io.mret_work 821 | io.sret_work := CSR_module.io.sret_work 822 | 823 | when (io.inst_reserved === 1.U) { 824 | // fill with instruction itself 825 | // TODO: deal with unaligned related exceptions 826 | CSR_badaddr := io.es_instr 827 | } .elsewhen (io.es_excode === excode_const.InstructionMisaligned) { 828 | CSR_badaddr := io.es_pc 829 | } .elsewhen (io.es_excode === excode_const.LoadAddrMisaligned || io.es_excode === excode_const.StoreAddrMisaligned) { 830 | CSR_badaddr := io.data_addr 831 | } .otherwise { 832 | CSR_badaddr := 0.U 833 | } 834 | 835 | when (io.es_excode === excode_const.InstructionMisaligned) { 836 | CSR_fault_addr := io.es_pc 837 | } .elsewhen (io.es_excode === excode_const.LoadAddrMisaligned || io.es_excode === excode_const.StoreAddrMisaligned) { 838 | CSR_fault_addr := io.data_addr 839 | } .otherwise { 840 | CSR_fault_addr := 0.U 841 | } 842 | 843 | when (io.es_csr === 1.U && io.es_new_instr === 1.U && io.es_ex === 0.U) { 844 | CSR_write := 1.U 845 | } .otherwise { 846 | CSR_write := 0.U 847 | } 848 | 849 | when (io.es_csr === 1.U) { 850 | CSR_op := 1.U 851 | } .otherwise { 852 | CSR_op := 0.U 853 | } 854 | 855 | CSR_fault_instr := io.es_instr 856 | CSR_read_num := io.Csr_num 857 | CSR_write_num := io.Csr_num 858 | } -------------------------------------------------------------------------------- /src/main/scala/Xim/priviledge.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import chisel3._ 4 | 5 | object priv_consts extends PriviledgeLevelConstants 6 | 7 | class PriviledgeReg extends Module { 8 | val io = IO(new Bundle { 9 | val wen = Input(Bool()) 10 | val wlevel = Input(UInt(2.W)) 11 | val rlevel = Output(UInt(2.W)) 12 | }) 13 | 14 | val priviledge_level = RegInit(3.U(2.W)) //initialized as Machine level 15 | 16 | when(io.wen) { 17 | priviledge_level := io.wlevel 18 | } 19 | 20 | io.rlevel := priviledge_level 21 | } 22 | 23 | class PriviledgeSignal extends Module { 24 | val io = IO(new Bundle { 25 | val es_valid = Input(UInt(1.W)) 26 | val es_ex_work = Input(UInt(1.W)) 27 | val mret_work = Input(UInt(1.W)) 28 | val sret_work = Input(UInt(1.W)) 29 | 30 | val mstatus_mpp = Input(UInt(2.W)) 31 | val sstatus_spp = Input(UInt(1.W)) 32 | 33 | val priv_level = Output(UInt(2.W)) 34 | 35 | val deleg_trap = Input(Bool()) 36 | }) 37 | 38 | //priviledge level 39 | val priv_level = Module(new PriviledgeReg) 40 | val priv_wen = Wire(Bool()) 41 | val priv_wlevel = Wire(UInt(2.W)) 42 | val priv_rlevel = Wire(UInt(2.W)) 43 | val next_priv_level = Wire(UInt(2.W)) 44 | 45 | priv_level.io.wen := priv_wen 46 | priv_level.io.wlevel := priv_wlevel 47 | priv_rlevel := priv_level.io.rlevel 48 | priv_wlevel := next_priv_level 49 | 50 | io.priv_level := priv_rlevel 51 | 52 | when (io.es_valid === 1.U && io.mret_work === 1.U && priv_rlevel === priv_consts.Machine) { 53 | next_priv_level := io.mstatus_mpp 54 | } .elsewhen (io.es_valid === 1.U && io.sret_work === 1.U && priv_rlevel === priv_consts.Supervisor) { 55 | next_priv_level := io.sstatus_spp 56 | } .elsewhen (io.es_ex_work === 1.U) { 57 | when (io.deleg_trap === true.B) { 58 | next_priv_level := priv_consts.Supervisor 59 | } .otherwise { 60 | next_priv_level := priv_consts.Machine 61 | } 62 | } .otherwise { 63 | next_priv_level := priv_consts.Machine 64 | } 65 | 66 | when (io.es_valid === 1.U && (io.mret_work === 1.U || io.sret_work === 1.U)) { 67 | priv_wen := true.B 68 | } .elsewhen (io.es_ex_work === 1.U) { 69 | priv_wen := true.B 70 | } .otherwise { 71 | priv_wen := false.B 72 | } 73 | } -------------------------------------------------------------------------------- /src/main/scala/Xim/ptw.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | /* Note that this is still under development */ 4 | 5 | import Chisel.switch 6 | import Chisel.Cat 7 | import chisel3._ 8 | import chisel3.util._ 9 | 10 | /* This is the page table walker for TLB to call */ 11 | /* I would like to use AXI crossbar to split between CPU Core and PTW so we will provide an AXI interface here */ 12 | class PTW(width:Int = 64) extends Module { 13 | val io = IO(new Bundle{ 14 | // SRAM-like inst channel 15 | val inst_req = Output(UInt(1.W)) 16 | val inst_wr = Output(UInt(1.W)) 17 | val inst_size = Output(UInt(2.W)) 18 | val inst_addr = Output(UInt(width.W)) 19 | val inst_wdata = Output(UInt(width.W)) 20 | val inst_rdata = Input(UInt(width.W)) 21 | val inst_addr_ok = Input(UInt(1.W)) 22 | val inst_data_ok = Input(UInt(1.W)) 23 | 24 | // TLB related 25 | val TLB_entry = Output(UInt((new TLB_entry).getWidth.W)) 26 | val TLB_entry_valid = Output(UInt(1.W)) 27 | val req_vaddr = Input(UInt(width.W)) 28 | val req_valid = Input(UInt(1.W)) 29 | val satp_base = Input(UInt(width.W)) 30 | }) 31 | 32 | val inst_addr = Wire(UInt(width.W)) 33 | val inst_data = Wire(UInt(width.W)) 34 | val inst_req_valid = Wire(UInt(1.W)) 35 | val inst_req_valid_r = RegInit(0.U(1.W)) 36 | val inst_req_ack = Wire(UInt(1.W)) 37 | val inst_valid = Wire(UInt(1.W)) 38 | 39 | 40 | // SRAM-like inst channel 41 | io.inst_req := inst_req_valid 42 | io.inst_wr := 0.U 43 | io.inst_size := 3.U // 64 bit 44 | io.inst_addr := inst_addr 45 | io.inst_wdata := 0.U 46 | inst_data := io.inst_rdata 47 | inst_req_ack := io.inst_addr_ok 48 | inst_valid := io.inst_data_ok 49 | 50 | // begin actual page table walker related 51 | // the behaviour of a second request before the first request is finished is UNDEFINED 52 | val vaddr = RegInit(0.U.asTypeOf(new VAddr)) 53 | val req_valid = RegInit(0.U(1.W)) 54 | 55 | val TLB_entry_r = Reg(new TLB_entry) 56 | val TLB_entry_valid_set = RegInit(0.U(1.W)) 57 | val TLB_entry_valid = Wire(UInt(1.W)) 58 | val page_table_r = RegInit(0.U.asTypeOf(new PTE)) 59 | val VPN_fetched = Wire(UInt(1.W)) 60 | val is_leaf = Wire(UInt(1.W)) 61 | val addr_handshake = Wire(UInt(1.W)) 62 | val data_handshake = Wire(UInt(1.W)) 63 | 64 | addr_handshake := (inst_req_valid & inst_req_ack) 65 | data_handshake := (inst_valid) 66 | VPN_fetched := data_handshake 67 | 68 | when (io.req_valid === 1.U) { 69 | vaddr := io.req_vaddr.asTypeOf(new VAddr) 70 | req_valid := io.req_valid 71 | } .elsewhen (TLB_entry_valid === 1.U) { 72 | vaddr := 0.U.asTypeOf(new VAddr) 73 | req_valid := 0.U 74 | } 75 | 76 | when (io.req_valid === 1.U) { 77 | TLB_entry_valid_set := 0.U 78 | } .elsewhen (TLB_entry_valid === 1.U) { 79 | TLB_entry_valid_set := 1.U 80 | } 81 | 82 | // state machine here 83 | // sInit: the initial state, will move to sVPN2 when new request come, hold the current data 84 | // sVPN2: fetching the top level page table, when fetched, if leaf go to sInit, otherwise go to sVPN1 85 | // sVPN1: fetching the second level page table, when fetched, if leaf go to sInit, otherwise go to sVPN0 86 | // sVPN0: fetching the leaf page table, when fetched, go to sInit 87 | val sfInit :: sfVPN2 :: sfVPN1 :: sfVPN0 :: Nil = Enum(4) 88 | val state = RegInit(sfInit) 89 | val fetched_leaf = Wire(UInt(1.W)) 90 | val fetched_non_leaf = Wire(UInt(1.W)) 91 | fetched_leaf := VPN_fetched === 1.U && is_leaf === 1.U 92 | fetched_non_leaf := VPN_fetched === 1.U && is_leaf === 0.U 93 | 94 | switch (state) { 95 | is(sfInit) { 96 | when (io.req_valid === 1.U) { 97 | state := sfVPN2 98 | } 99 | } 100 | is(sfVPN2) { 101 | when (fetched_leaf === 1.U) { 102 | state := sfInit 103 | } .elsewhen (fetched_non_leaf === 1.U) { 104 | state := sfVPN1 105 | } 106 | } 107 | is(sfVPN1) { 108 | when (fetched_leaf === 1.U) { 109 | state := sfInit 110 | } .elsewhen (fetched_non_leaf === 1.U) { 111 | state := sfVPN0 112 | } 113 | } 114 | is(sfVPN0) { 115 | when (fetched_leaf === 1.U) { 116 | // software will ensure that this is a leaf page 117 | state := sfInit 118 | } 119 | } 120 | } 121 | 122 | 123 | inst_req_valid := inst_req_valid_r 124 | when (io.req_valid === 1.U) { 125 | inst_req_valid_r := 1.U 126 | } .elsewhen (fetched_non_leaf === 1.U && state =/= sfVPN0) { 127 | inst_req_valid_r := 1.U 128 | } .elsewhen (inst_req_ack === 1.U) { 129 | inst_req_valid_r := 0.U 130 | } 131 | 132 | 133 | is_leaf := (page_table_r.X | page_table_r.R | page_table_r.W) 134 | // inst_addr generation 135 | // the very beginning address is satp_base + VPN2 136 | // the following address is PPN + VPNx 137 | when (state === sfVPN2) { 138 | inst_addr := io.satp_base + vaddr.VPN2 139 | } .elsewhen (state === sfVPN1) { 140 | inst_addr := Cat(page_table_r.PPN2, page_table_r.PPN1, page_table_r.PPN0) + vaddr.VPN1 141 | } .elsewhen (state === sfVPN0) { 142 | inst_addr := Cat(page_table_r.PPN2, page_table_r.PPN1, page_table_r.PPN0) + vaddr.VPN0 143 | } .otherwise { 144 | inst_addr := 0.U 145 | } 146 | 147 | 148 | // TLB_entry_r is somewhat complex here 149 | TLB_entry_r.D := page_table_r.D 150 | TLB_entry_r.A := page_table_r.A 151 | TLB_entry_r.G := page_table_r.G 152 | TLB_entry_r.U := page_table_r.U 153 | TLB_entry_r.X := page_table_r.X 154 | TLB_entry_r.W := page_table_r.W 155 | TLB_entry_r.R := page_table_r.R 156 | TLB_entry_r.V := page_table_r.V 157 | 158 | when (state === sfVPN2 && fetched_leaf === 1.U) { 159 | TLB_entry_r.page_size := 2.U // 1GB huge page 160 | TLB_entry_r.VPN2 := vaddr.VPN2 161 | TLB_entry_r.VPN1 := 0.U 162 | TLB_entry_r.VPN0 := 0.U 163 | TLB_entry_r.PPN2 := page_table_r.PPN2 164 | // TODO: add exceptions here 165 | // note that a exception should be thrown here if PPN1 or PPN0 is non-zero 166 | TLB_entry_r.PPN1 := 0.U 167 | TLB_entry_r.PPN0 := 0.U 168 | 169 | } .elsewhen (state === sfVPN1 && fetched_leaf === 1.U) { 170 | TLB_entry_r.page_size := 2.U // 1GB huge page 171 | TLB_entry_r.VPN2 := vaddr.VPN2 172 | TLB_entry_r.VPN1 := vaddr.VPN1 173 | TLB_entry_r.VPN0 := 0.U 174 | TLB_entry_r.PPN2 := page_table_r.PPN2 175 | // TODO: add exceptions here 176 | // note that a exception should be thrown here if PPN0 is non-zero 177 | TLB_entry_r.PPN1 := page_table_r.PPN1 178 | TLB_entry_r.PPN0 := 0.U 179 | } .elsewhen (state === sfVPN0 && fetched_leaf === 1.U) { 180 | TLB_entry_r.page_size := 2.U // 1GB huge page 181 | TLB_entry_r.VPN2 := vaddr.VPN2 182 | TLB_entry_r.VPN1 := vaddr.VPN1 183 | TLB_entry_r.VPN0 := vaddr.VPN0 184 | TLB_entry_r.PPN2 := page_table_r.PPN2 185 | // TODO: add exceptions here 186 | // note that a exception should be thrown here if the PPN1 or PPN0 is non-zero 187 | TLB_entry_r.PPN1 := page_table_r.PPN1 188 | TLB_entry_r.PPN0 := page_table_r.PPN0 189 | } 190 | 191 | io.TLB_entry := TLB_entry_r.asUInt() 192 | io.TLB_entry_valid := TLB_entry_valid & !TLB_entry_valid_set 193 | TLB_entry_valid := fetched_leaf 194 | 195 | when (data_handshake === 1.U) { 196 | //page_table_r := inst_data 197 | } 198 | 199 | 200 | // todo 201 | VPN_fetched := 0.U 202 | } 203 | 204 | object PTW extends App { 205 | chisel3.Driver.execute(args, () => new PTW(64)) 206 | } -------------------------------------------------------------------------------- /src/main/scala/Xim/ptw_independent.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | /* This is intended for the test of Page Table Walker */ 4 | 5 | import chisel3._ 6 | 7 | class ptw_independent(width: Int = 64) extends Module { 8 | val io = IO(new Bundle{ 9 | val VAddr = Input(UInt(width.W)) 10 | val VAddr_valid = Input(UInt(1.W)) 11 | val TLB_entry_valid = Output(UInt(1.W)) 12 | val TLB_entry = Output(UInt((new TLB_entry).getWidth.W)) 13 | }) 14 | // Provide an AXI RAM for ptw to walk on 15 | val bridge = Module(new AXI_Bridge(64)) 16 | val ram = Module(new AXI_ram) 17 | val ptw = Module(new PTW) 18 | 19 | ptw.io.req_vaddr := io.VAddr 20 | ptw.io.req_valid := io.VAddr_valid 21 | io.TLB_entry_valid := ptw.io.TLB_entry_valid 22 | io.TLB_entry := ptw.io.TLB_entry 23 | ptw.io.satp_base := 0x0.U 24 | 25 | bridge.io.clock := clock 26 | bridge.io.reset := reset 27 | 28 | bridge.io.inst_req := ptw.io.inst_req 29 | bridge.io.inst_wr := 0.U 30 | bridge.io.inst_size := 3.U 31 | bridge.io.inst_addr := ptw.io.inst_addr 32 | bridge.io.inst_wdata := 0.U 33 | ptw.io.inst_data_ok := bridge.io.inst_data_ok 34 | ptw.io.inst_addr_ok := bridge.io.inst_addr_ok 35 | ptw.io.inst_rdata := bridge.io.inst_rdata 36 | 37 | bridge.io.data_req := 0.U 38 | bridge.io.data_wr := 0.U 39 | bridge.io.data_size := 0.U 40 | bridge.io.data_addr := 0.U 41 | bridge.io.data_wdata := 0.U 42 | // we do not care the output of data channel 43 | 44 | ram.io.awid := bridge.io.awid 45 | ram.io.awaddr := bridge.io.awaddr 46 | ram.io.awlen := bridge.io.awlen 47 | ram.io.awsize := bridge.io.awsize 48 | ram.io.awburst := bridge.io.awburst 49 | ram.io.awlock := bridge.io.awlock 50 | ram.io.awcache := bridge.io.awcache 51 | ram.io.awprot := bridge.io.awprot 52 | ram.io.awvalid := bridge.io.awvalid 53 | bridge.io.awready := ram.io.awready 54 | ram.io.wdata := bridge.io.wdata 55 | ram.io.wstrb := bridge.io.wstrb 56 | ram.io.wlast := bridge.io.wlast 57 | ram.io.wvalid := bridge.io.wvalid 58 | bridge.io.wready := ram.io.wready 59 | bridge.io.bid := ram.io.bid 60 | bridge.io.bresp := ram.io.bresp 61 | bridge.io.bvalid := ram.io.bvalid 62 | ram.io.bready := bridge.io.bready 63 | ram.io.arid := bridge.io.arid 64 | ram.io.araddr := bridge.io.araddr 65 | ram.io.arlen := bridge.io.arlen 66 | ram.io.arsize := bridge.io.arsize 67 | ram.io.arburst := bridge.io.arburst 68 | ram.io.arlock := bridge.io.arlock 69 | ram.io.arcache := bridge.io.arcache 70 | ram.io.arprot := bridge.io.arcache 71 | ram.io.arvalid := bridge.io.arvalid 72 | bridge.io.arready := ram.io.arready 73 | bridge.io.rid := ram.io.rid 74 | bridge.io.rdata := ram.io.rdata 75 | bridge.io.rresp := ram.io.rresp 76 | bridge.io.rlast := ram.io.rlast 77 | bridge.io.rvalid := ram.io.rvalid 78 | ram.io.rready := bridge.io.rready 79 | 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/scala/Xim/reg.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import chisel3._ 4 | 5 | class RegFile(readPorts: Int) extends Module { 6 | val io = IO(new Bundle { 7 | val wen = Input(Bool()) 8 | val waddr = Input(UInt(5.W)) 9 | val wdata = Input(UInt(64.W)) 10 | val raddr = Input(Vec(readPorts, UInt(5.W))) 11 | val rdata = Output(Vec(readPorts, UInt(64.W))) 12 | val debug_a0 = Output(UInt(64.W)) 13 | }) 14 | 15 | val regs = RegInit(VecInit(Seq.fill(32)(0.U(64.W)))) 16 | 17 | when(io.wen & io.waddr =/= 0.U) { 18 | regs(io.waddr) := io.wdata 19 | } 20 | 21 | for (i <- 0 until readPorts) { 22 | io.rdata(i) := regs(io.raddr(i)) 23 | } 24 | 25 | io.debug_a0 := regs(10) // a0 is for debug purpose 26 | 27 | } -------------------------------------------------------------------------------- /src/main/scala/Xim/tlb.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import Chisel.{OHToUInt, log2Ceil} 4 | import chisel3._ 5 | import chisel3.util 6 | 7 | /* A WIP TLB interface */ 8 | 9 | /* a variable entry count TLB module */ 10 | class tlb(TLB_entry_count: Int = 8, width: Int = 64) extends Module { 11 | val io = IO(new Bundle { 12 | val VAddr = Input(UInt(width.W)) 13 | val PAddr = Output(UInt(width.W)) 14 | val PAddr_valid = Output(UInt(1.W)) 15 | val TLB_ex = Output(UInt(1.W)) 16 | val TLB_excode = Output(UInt(5.W)) 17 | // TODO: add memory port here 18 | }) 19 | // we will drive PTW in this module 20 | val tlb_entry = RegInit(VecInit(Seq.fill(TLB_entry_count)(0.U.asTypeOf(new TLB_entry)))) 21 | val tlb_match = Wire(Vec(TLB_entry_count, UInt(1.W))) 22 | val tlb_match_index = WireInit(OHToUInt(tlb_match.asUInt())) 23 | val tlb_matched = Wire(UInt(1.W)) 24 | 25 | val tlb_VAddr = WireInit(io.VAddr.asTypeOf(new VAddr)) 26 | val tlb_PAddr = Wire(new PAddr) 27 | 28 | io.PAddr := tlb_PAddr.asUInt() 29 | 30 | val tlb_write_index = RegInit(0.U(log2Ceil(TLB_entry_count).W)) 31 | 32 | // page table walker 33 | val ptw = Module(new PTW(width)) 34 | val tlb_write = Wire(UInt(1.W)) 35 | val tlb_entry_ptw = Wire(UInt((new TLB_entry).getWidth.W)) 36 | tlb_write := ptw.io.TLB_entry_valid 37 | tlb_entry_ptw := ptw.io.TLB_entry 38 | 39 | for (i <- 0 until TLB_entry_count) { 40 | when (tlb_entry(i).V === 1.U && ( 41 | (tlb_entry(i).page_size === 0.U && 42 | tlb_VAddr.VPN0 === tlb_entry(i).VPN0 && 43 | tlb_VAddr.VPN1 === tlb_entry(i).VPN1 && 44 | tlb_VAddr.VPN2 === tlb_entry(i).VPN2) || 45 | (tlb_entry(i).page_size === 1.U && 46 | tlb_VAddr.VPN1 === tlb_entry(i).VPN1 && 47 | tlb_VAddr.VPN2 === tlb_entry(i).VPN2) || 48 | (tlb_entry(i).page_size === 2.U && 49 | tlb_VAddr.VPN2 === tlb_entry(i).VPN2) 50 | )) { 51 | // type1: 4KB 52 | tlb_match(i) := 1.U 53 | } .otherwise { 54 | tlb_match(i) := 0.U 55 | } 56 | } 57 | 58 | tlb_matched := (tlb_match.asUInt() =/= 0.U) 59 | io.PAddr_valid := tlb_matched 60 | 61 | // PAddr here is complex 62 | tlb_PAddr.offset := tlb_VAddr.offset 63 | when (tlb_matched === 1.U && tlb_entry(tlb_match_index).page_size === 0.U) { 64 | tlb_PAddr.PPN0 := tlb_entry(tlb_match_index).PPN0 65 | } .otherwise { 66 | tlb_PAddr.PPN0 := 0.U 67 | } 68 | when (tlb_matched === 1.U && tlb_entry(tlb_match_index).page_size < 2.U) { 69 | tlb_PAddr.PPN1 := tlb_entry(tlb_match_index).PPN1 70 | } .otherwise { 71 | tlb_PAddr.PPN1 := 0.U 72 | } 73 | 74 | when (tlb_matched === 1.U && tlb_entry(tlb_match_index).page_size < 3.U) { 75 | tlb_PAddr.PPN2 := tlb_entry(tlb_match_index).PPN2 76 | } .otherwise { 77 | tlb_PAddr.PPN2 := 0.U 78 | } 79 | tlb_PAddr.Zero := 0.U 80 | 81 | // todo: 82 | io.TLB_ex := 0.U 83 | io.TLB_excode := 0.U 84 | } 85 | 86 | object tlb extends App { 87 | chisel3.Driver.execute(args, () => new tlb(32, 64)) 88 | } -------------------------------------------------------------------------------- /src/test/scala/Xim/ALUMain.scala: -------------------------------------------------------------------------------- 1 | // See README.md for license details. 2 | 3 | package Xim 4 | 5 | import chisel3._ 6 | 7 | /** 8 | * This provides an alternate way to run tests, by executing then as a main 9 | * From sbt (Note: the test: prefix is because this main is under the test package hierarchy): 10 | * {{{ 11 | * test:runMain Xim.ALUMain 12 | * }}} 13 | * To see all command line options use: 14 | * {{{ 15 | * test:runMain Xim.ALUMain --help 16 | * }}} 17 | * To run with verilator: 18 | * {{{ 19 | * test:runMain Xim.ALUMain --backend-name verilator 20 | * }}} 21 | * To run with verilator from your terminal shell use: 22 | * {{{ 23 | * sbt 'test:runMain Xim.ALUMain --backend-name verilator' 24 | * }}} 25 | */ 26 | object ALUMain extends App { 27 | iotesters.Driver.execute(args, () => new ALU) { 28 | c => new ALUUnitTester(c) 29 | } 30 | } 31 | 32 | /** 33 | * This provides a way to run the firrtl-interpreter REPL (or shell) 34 | * on the lowered firrtl generated by your circuit. You will be placed 35 | * in an interactive shell. This can be very helpful as a debugging 36 | * technique. Type help to see a list of commands. 37 | * 38 | * To run from sbt 39 | * {{{ 40 | * test:runMain gcd.GCDRepl 41 | * }}} 42 | * To run from sbt and see the half a zillion options try 43 | * {{{ 44 | * test:runMain gcd.GCDRepl --help 45 | * }}} 46 | */ 47 | object ALURepl extends App { 48 | iotesters.Driver.executeFirrtlRepl(args, () => new ALU) 49 | } -------------------------------------------------------------------------------- /src/test/scala/Xim/ALUUnitTest.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import chisel3.iotesters 4 | import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester} 5 | 6 | class ALUUnitTester(c: ALU) extends PeekPokeTester(c) { 7 | private val alu = c 8 | 9 | /* 10 | poke(alu.io.alu_src1, 6) 11 | poke(alu.io.alu_src2, 7) 12 | poke(alu.io.alu_op, 2) // slt 13 | expect(alu.io.alu_result, 1) 14 | expect(alu.io.alu_overflow, 0) 15 | 16 | */ 17 | 18 | poke(alu.io.alu_src1, -1) 19 | poke(alu.io.alu_src2, 7) 20 | poke(alu.io.alu_op, 4) // slt 21 | expect(alu.io.alu_result, 1) 22 | expect(alu.io.alu_overflow, 0) 23 | 24 | /* 25 | poke(alu.io.alu_src1, 6) 26 | poke(alu.io.alu_src2, 7) 27 | poke(alu.io.alu_op, 1) // add 28 | expect(alu.io.alu_result, 13L) 29 | expect(alu.io.alu_overflow, 0) 30 | 31 | poke(alu.io.alu_src1, 6) 32 | poke(alu.io.alu_src2, -2) // 0xfffffffe 33 | poke(alu.io.alu_op, 1) // add 34 | expect(alu.io.alu_result, 4L) 35 | expect(alu.io.alu_overflow, 0) 36 | 37 | poke(alu.io.alu_src1, 6) 38 | poke(alu.io.alu_src2, 2147483647) // 0xfffffffe 39 | poke(alu.io.alu_op, 1) // add 40 | expect(alu.io.alu_result, 2147483653L) 41 | expect(alu.io.alu_overflow, 1) 42 | 43 | // poke(alu.io.alu_src1, 6) // dont care 44 | poke(alu.io.alu_src2, 2147483647) // 0xfffffffe 45 | poke(alu.io.alu_op, 0x800) // add 46 | expect(alu.io.alu_result, 0x7fff0000L) 47 | // expect(alu.io.alu_overflow, 0) // dont care 48 | 49 | poke(alu.io.alu_src1, 16) 50 | poke(alu.io.alu_src2, 0xffff0000L) 51 | poke(alu.io.alu_op, 0x400) // sra 52 | expect(alu.io.alu_result, 0xffffffffL) 53 | 54 | poke(alu.io.alu_src1, 16) 55 | poke(alu.io.alu_src2, 0xffff0000L) 56 | poke(alu.io.alu_op, 0x200) // sra 57 | expect(alu.io.alu_result, 0xffffL) 58 | 59 | */ 60 | } -------------------------------------------------------------------------------- /src/test/scala/Xim/AXI_RAM_Main.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import chisel3._ 4 | /* 5 | object AXI_RAM_Main extends App { 6 | iotesters.Driver.execute(args, () => new AXI_ram) { 7 | c => new AXI_RAM_UnitTester(c) 8 | } 9 | } 10 | 11 | */ 12 | -------------------------------------------------------------------------------- /src/test/scala/Xim/AXI_RAM_UnitTest.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import chisel3._ 4 | import chisel3.iotesters.PeekPokeTester 5 | /* 6 | class AXI_RAM_UnitTester(c: AXI_ram) extends PeekPokeTester(c) { 7 | private val ram = c 8 | poke(ram.io.arid, 0) 9 | poke(ram.io.araddr, 3) 10 | poke(ram.io.arlen, 0) 11 | poke(ram.io.arsize, 0) // single byte 12 | poke(ram.io.arburst, 0) 13 | poke(ram.io.arlock, 0) 14 | poke(ram.io.arcache, 0) 15 | poke(ram.io.arprot, 0) 16 | poke(ram.io.arvalid, 1) 17 | step(10) 18 | 19 | } 20 | 21 | */ -------------------------------------------------------------------------------- /src/test/scala/Xim/CPU_Core_Main.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import chisel3._ 4 | /* 5 | object CPU_Core_Main extends App { 6 | iotesters.Driver.execute(args, () => new CPU_Core) { 7 | c => new CPU_Core_Branch_UnitTester(c) 8 | } 9 | /* 10 | iotesters.Driver.execute(args, () => new CPU_Core) { 11 | c => new CPU_Core_Arithmetic_UnitTester(c) 12 | } 13 | */ 14 | } 15 | 16 | 17 | */ -------------------------------------------------------------------------------- /src/test/scala/Xim/CPU_Core_UnitTest.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import chisel3._ 4 | import chisel3.iotesters.PeekPokeTester 5 | /* 6 | class CPU_Core_Arithmetic_UnitTester(c: CPU_Core) extends PeekPokeTester(c) { 7 | private val core = c 8 | step(1) // come into a stable state 9 | printf("cycle 1\n") 10 | expect(c.io.inst_req_valid, 1) 11 | poke(c.io.inst_ack, 1) // made a handshake 12 | step(1) 13 | printf("cycle 2\n") 14 | expect(c.io.inst_addr, 0) 15 | expect(c.io.inst_ack, 1) 16 | step(2) // wait a little longer 17 | printf("cycle 4\n") 18 | poke(c.io.inst_valid, 1) 19 | poke(c.io.inst_data, 0x06400093) 20 | step(2) 21 | printf("cycle 6\n") 22 | expect(c.io.reg_wen, 1) 23 | expect(c.io.reg_waddr, 1) 24 | expect(c.io.reg_wdata, 100) 25 | } 26 | 27 | class CPU_Core_Branch_UnitTester(c: CPU_Core) extends PeekPokeTester(c) { 28 | private val core = c 29 | poke(c.io.inst_req_ack, 0) 30 | poke(c.io.inst_valid, 0) 31 | poke(c.io.data_req_ack, 0) 32 | poke(c.io.data_read_valid, 0) 33 | step(1) // come into a stable state 34 | print("**********************cycle 1**********************\n") 35 | expect(c.io.inst_req_valid, 1) 36 | poke(c.io.inst_ack, 1) // made a handshake 37 | step(1) 38 | print("**********************cycle 2**********************\n") 39 | expect(c.io.inst_addr, 0) 40 | expect(c.io.inst_ack, 1) 41 | step(2) // wait a little longer 42 | print("**********************cycle 4**********************\n") 43 | poke(c.io.inst_valid, 1) 44 | poke(c.io.inst_data, 0x00000863) 45 | step(1) 46 | print("**********************cycle 5**********************\n") 47 | poke(c.io.inst_ack, 1) 48 | poke(c.io.inst_valid, 1) 49 | poke(c.io.inst_data, 0x06408013) // continue providing inst data 50 | 51 | step(1) 52 | print("**********************cycle 6**********************\n") 53 | 54 | step(1) 55 | print("**********************cycle 7**********************\n") 56 | 57 | step(1) 58 | print("**********************cycle 8**********************\n") 59 | 60 | step(1) 61 | print("**********************cycle 9**********************\n") 62 | 63 | step(1) 64 | print("**********************cycle 10**********************\n") 65 | 66 | step(1) 67 | print("**********************cycle 11**********************\n") 68 | 69 | } 70 | 71 | */ 72 | 73 | -------------------------------------------------------------------------------- /src/test/scala/Xim/CSR_Main.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import chisel3._ 4 | 5 | object CSR_Main extends App { 6 | iotesters.Driver.execute(args, () => new CSR) { 7 | c => new CSR_UnitTester(c) 8 | } 9 | } -------------------------------------------------------------------------------- /src/test/scala/Xim/CSR_UnitTest.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import chisel3._ 4 | import chisel3.iotesters.PeekPokeTester 5 | 6 | class CSR_UnitTester(c: CSR) extends PeekPokeTester(c) { 7 | private val csr = c 8 | // EPC 9 | poke(csr.io.es_csr_wr, 1) 10 | poke(csr.io.es_csr_write_num, 0x341) 11 | poke(csr.io.es_csr_write_data, 0x2333) 12 | poke(csr.io.es_csr_read_num, 0x341) 13 | step(1) 14 | expect(csr.io.es_csr_read_data, 0x2333) 15 | 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/test/scala/Xim/PTWMain.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import chisel3._ 4 | import chisel3.iotesters._ 5 | 6 | /* 7 | object PTWMain extends App { 8 | iotesters.Driver.execute(args, () => new PTW) { 9 | c => new PTW_UnitTester(c) 10 | } 11 | } 12 | 13 | */ -------------------------------------------------------------------------------- /src/test/scala/Xim/PTWUnitTest.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import Chisel.iotesters.PeekPokeTester 4 | import chisel3._ 5 | /* 6 | class PTW_UnitTester (c: PTW) extends PeekPokeTester(c) { 7 | 8 | 9 | 10 | } 11 | 12 | 13 | */ -------------------------------------------------------------------------------- /src/test/scala/Xim/SoC_Main.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import chisel3._ 4 | import firrtl.stage.RunFirrtlTransformAnnotation 5 | 6 | object SoC_Main_Type_One extends App { 7 | iotesters.Driver.execute(args, () => new SoC) { 8 | c => new SoC_UnitTester_Type1(c) 9 | } 10 | } 11 | 12 | object SoC_Main_Type_Two extends App { 13 | iotesters.Driver.execute(args, () => new SoC) { 14 | c => new SoC_UnitTester_Type2(c) 15 | } 16 | } 17 | 18 | object SoC_Main_Type_Three extends App { 19 | iotesters.Driver.execute(args, () => new SoC) { 20 | c => new SoC_UnitTester_Type3(c) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/scala/Xim/SoC_UnitTest.scala: -------------------------------------------------------------------------------- 1 | package Xim 2 | 3 | import scala.util.control.Breaks._ 4 | import scala.io.Source 5 | import chisel3.iotesters.PeekPokeTester 6 | 7 | class SoC_UnitTester_Type1(c: SoC) extends PeekPokeTester(c) { 8 | // private val SoC = c 9 | var expected_pc: BigInt = 0 10 | var prev_pc: BigInt = 0 11 | var curr_pc: BigInt = 0 12 | var curr_inst: BigInt = 0 13 | var inst_count: BigInt = 0 14 | val filename = "/Users/cgk/ownCloud/课程/一生一芯/ict/golden_trace.txt" 15 | step(16) // tricky here: reset to normal 16 | breakable { 17 | for (line <- Source.fromFile(filename).getLines) { 18 | inst_count += 1 19 | val tmp_line = line.substring(0, 8) 20 | expected_pc = java.lang.Long.parseLong(tmp_line, 16) 21 | // we have fetched our expected pc from trace file, trying to figure out our actual pc 22 | do { 23 | step(1) 24 | curr_pc = peek(c.io.es_pc) 25 | curr_inst = peek(c.io.es_instr) 26 | // if we are still in the previous instruction or in invalid slot, continue 27 | } while (curr_pc == prev_pc || curr_inst == 0x33) 28 | 29 | if (curr_pc != expected_pc) { 30 | printf(s"Fail at inst_count %x, expected pc = %x, actual pc = %x\n", inst_count, expected_pc, curr_pc) 31 | break() 32 | } 33 | //printf(s"current pc = %x, ", curr_pc) 34 | prev_pc = curr_pc 35 | //printf(s"debug: ${inst_count}\n") 36 | } 37 | } 38 | } 39 | 40 | class SoC_UnitTester_Type2(c: SoC) extends PeekPokeTester(c) { 41 | // testbench that ends with an ecall 42 | 43 | var i:Int = 0 44 | 45 | while (i < 1000000 && peek(c.io.es_instr) != BigInt(0x73)) { 46 | step(1) 47 | i += 1 48 | } 49 | expect(c.io.es_reg_a0, 0) // expect a0 to be zero 50 | 51 | /* after test, trigger an exception as a test end */ 52 | /* still run a few steps */ 53 | step(200) 54 | } 55 | 56 | class SoC_UnitTester_Type3(c: SoC) extends PeekPokeTester(c) { 57 | // mostly type 1, without trace compare enabled 58 | var expected_pc: BigInt = 0 59 | var prev_pc: BigInt = 0 60 | var curr_pc: BigInt = 0 61 | var curr_inst: BigInt = 0 62 | var inst_count: BigInt = 0 63 | val filename = "/Users/cgk/ownCloud/课程/一生一芯/ict/golden_trace.txt" 64 | step(16) // tricky here: reset to normal 65 | var i = 0 66 | breakable { 67 | for (i <- 1 to 500000) { 68 | inst_count += 1 69 | // we have fetched our expected pc from trace file, trying to figure out our actual pc 70 | do { 71 | step(1) 72 | curr_pc = peek(c.io.es_pc) 73 | curr_inst = peek(c.io.es_instr) 74 | // if we are still in the previous instruction or in invalid slot, continue 75 | } while (curr_pc == prev_pc || curr_inst == 0x33) 76 | 77 | //printf(s"current pc = %x, ", curr_pc) 78 | prev_pc = curr_pc 79 | //printf(s"debug: ${inst_count}\n") 80 | } 81 | } 82 | } --------------------------------------------------------------------------------