├── .gitignore
├── .gitmodules
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── build.sbt
├── setup.sh
├── src
└── main
│ └── scala
│ └── bottlerocket
│ ├── AXI4Lite.scala
│ ├── BottleRocketCore.scala
│ ├── BottleRocketGenerator.scala
│ ├── DebugModuleFSM.scala
│ ├── DebugStepper.scala
│ ├── ExceptionCause.scala
│ ├── FrontendBuffer.scala
│ ├── LoadExtender.scala
│ ├── Params.scala
│ ├── RVFI.scala
│ └── RegfileWithZero.scala
└── test
├── BottleRocketCoreTB.v
├── Makefile
├── MockAXI4LiteSRAM.v
└── test.ld
/.gitignore:
--------------------------------------------------------------------------------
1 | # Temporary files
2 | *~
3 | *#
4 |
5 | # File extensions
6 | *.swp
7 | *.objdump
8 | *.o
9 | *.svwf
10 | *.dump
11 | *.log
12 | *.elf
13 | *.hex
14 | *.trn
15 | *.dsn
16 | test/*.d
17 | test/*.ld
18 | test/*.addrs
19 |
20 | # Directories
21 | /generated-src/
22 | /path-check-output/
23 | /lib/
24 | /target/
25 | /project/target/
26 | /test/target/
27 | *.simvision/
28 | */INCA_libs/
29 | */ncverilog.history
30 |
31 | # Specific files
32 | .addons-dont-touch
33 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "third_party/rocket-chip"]
2 | path = third_party/rocket-chip
3 | url = https://github.com/freechipsproject/rocket-chip
4 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | We'd love to accept your patches and contributions to this project. There are
4 | just a few small guidelines you need to follow.
5 |
6 | ## Contributor License Agreement
7 |
8 | Contributions to this project must be accompanied by a Contributor License
9 | Agreement. You (or your employer) retain the copyright to your contribution;
10 | this simply gives us permission to use and redistribute your contributions as
11 | part of the project. Head over to to see
12 | your current agreements on file or to sign a new one.
13 |
14 | You generally only need to submit a CLA once, so if you've already submitted one
15 | (even if it was for a different project), you probably don't need to do it
16 | again.
17 |
18 | ## Code reviews
19 |
20 | All submissions, including submissions by project members, require review. We
21 | use GitHub pull requests for this purpose. Consult
22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
23 | information on using pull requests.
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # Copyright 2017 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | GENDIR := generated-src
16 |
17 | RVEC ?= 4100
18 |
19 | default: $(GENDIR)/BottleRocketCore.v
20 |
21 | .PHONY: $(GENDIR)/BottleRocketCore.v
22 | $(GENDIR)/BottleRocketCore.v:
23 | rm -rf generated-src/*
24 | sbt "runMain bottlerocket.BottleRocketGenerator --target-dir generated-src --reset-vec ${RVEC}"
25 |
26 | .PHONY: check-paths test clean
27 |
28 | check-paths:
29 | sbt "runMain bottlerocket.BottleRocketPathChecker --target-dir path-check-output --reset-vec ${RVEC}"
30 |
31 | test: $(GENDIR)/BottleRocketCore.v
32 | $(MAKE) -C test clean
33 | $(MAKE) -C test
34 |
35 | clean:
36 | $(MAKE) -C test clean
37 | rm -rf generated-src
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BottleRocket RV32IMC Core
2 |
3 | This is not an officially supported Google product.
4 |
5 | ## Overview
6 |
7 | BottleRocket is a 32-bit, RISC-V microcontroller-class processor core that is
8 | built as a customized microarchitecture from components of the Free Chips
9 | Project Rocket core. It is implemented in the Chisel HDL, and it consists of a
10 | basic, 3-stage pipeline with separate instruction and data ARM AMBA AXI4Lite
11 | buses. It has an assortment of features that are designed to support typical use
12 | as a control processor for memory-mapped devices.
13 |
14 | ## Features
15 |
16 | * RV32IMC ISA, Privileged Architecture v1.10
17 | * 32-bit RISC-V base instruction set (‘RV32I’)
18 | * Hardware integer multiplier/divider (‘M’ standard extension)
19 | * 16-bit compressed instruction support (‘C’ standard extension)
20 | * Machine (‘M’) and user (‘U’) privilege modes
21 |
22 | ## Design Rationale
23 |
24 | The BottleRocket core is designed to be as simple as possible to allow for easy,
25 | application-specific changes. It uses several key components from Rocket Chip,
26 | an open-source RISC-V chip generator framework, including the instruction
27 | decoder and control & status register (CSR) finite state machine. These two
28 | components are responsible for implementing the majority of the nuanced features
29 | of the user ISA and the privileged architecture, respectively. This approach has
30 | several key advantages.
31 |
32 | * Rocket Chip is the reference implementation of the RISC-V ISA. It is largely
33 | produced by the primary authors of the ISA specifications, and it is by far
34 | the most spec-compliant hardware implementation.
35 |
36 | * However, Rocket Chip is quite complex. It has many performance-oriented
37 | microarchitectural features (integrated non-blocking data cache, branch
38 | prediction)
39 |
40 | * Rocket Chip is a very heavily metaprogrammed framework for generating
41 | symmetric multiprocessor (SMP) systems with interconnect supporting multiple
42 | coherent caches. In order to use the core in a simpler context, creating a
43 | simpler top-level module would be desirable for readability purposes.
44 |
45 | * The “Rocket” core that is used in Rocket Chip is largely composed of
46 | well-factored, reasonably large, and highly-reusable sub-blocks. These blocks
47 | have been used in multiple projects to create different core microarchitectures
48 | or pipelines with relatively low effort (BOOM, ZScale)
49 |
50 | * The instruction decoder is implemented as a reusable combinational block that
51 | is essentially universally applicable to any RISC-V core where decode happens
52 | within a single stage. It is well-verified and supports all of the RISC-V
53 | standard extensions in their latest incarnations.
54 |
55 | * The RISC-V compressed (RVC) expander is also implemented as a reusable
56 | combinational block. Because every RVC instruction maps onto a normal 32-bit
57 | encoding, this universal expander handles all of the RVC extension, aside from
58 | the extra complication of designing fetch logic to handle 16-bit aligned
59 | program counters.
60 |
61 | * The CSR file implements essentially all of the privileged architecture as a
62 | state machine.
63 |
64 | * Building around Rocket components allows BottleRocket to be a fully
65 | spec-compliant RV32IMC core with machine and user modes while occupying a few
66 | hundred lines of total new Chisel code.
67 |
68 | ## Building and Running
69 |
70 | The first step to using BottleRocket is making sure that the work environment is
71 | ready to support RISC-V development. It is helpful to follow the convention that
72 | the RISCV environment variable points to the RISC-V toolchain installation.
73 |
74 | 1. Add the following to your environment using configuration files and/or a
75 | script
76 |
77 | ```bash
78 | $ export RISCV=
79 | $ export PATH=$PATH:$RISCV/bin
80 | ```
81 |
82 | 2. Clone and install the RV32IMC toolchain. Note, this requires changing the
83 | meta-build script that calls configure and make in each process, as shown
84 | with the sed invocation below.
85 |
86 | ```bash
87 | $ git clone https://github.com/riscv/riscv-tools
88 | $ cd riscv-tools
89 | $ sed 's/ima/imc/g' build-rv32imc.sh
90 | $ chmod +x build-rv32imc.sh
91 | $ ./build-rv32imc.sh
92 | ```
93 |
94 | 3. Enter the BottleRocket directory and run the standalone tests. NOTE: you may
95 | need to modify `test/Makefile` to target an appropriate Verilog simulator for
96 | your environment.
97 |
98 | ```bash
99 | $ cd
100 | $ make test
101 | ```
102 |
103 | 4. The generated Verilog is in `generated-src/BottleRocketCore.v` -- this
104 | contains the top level BottleRocketCore module that can be instantiated in a
105 | Verilog design.
106 |
107 |
108 | 5. Try running sbt (“Simple Build Tool,” the most popular build tool for Scala
109 | projects) manually. This allows more options for building the core. The
110 | following command will print all available command-line options (number of
111 | interrupt lines, target directory for Verilog generation, etc.).
112 |
113 | ```bash
114 | $ sbt "runMain bottlerocket.BottleRocketGenerator --help"
115 | ```
116 |
--------------------------------------------------------------------------------
/build.sbt:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)
16 |
17 | // managed dependencies
18 | val chisel3 = "edu.berkeley.cs" %% "chisel3" % "3.0-SNAPSHOT_2017-06-22"
19 | val scalatest = "org.scalatest" %% "scalatest" % "2.2.5"
20 | val scalacheck = "org.scalacheck" %% "scalacheck" % "1.12.4"
21 |
22 | lazy val commonSettings = Seq(
23 | name := "bottlerocket",
24 | version := "1.0",
25 | scalaVersion := "2.11.7",
26 | resolvers ++= Seq(
27 | Resolver.sonatypeRepo("snapshots"),
28 | Resolver.sonatypeRepo("releases")
29 | ),
30 | libraryDependencies ++= Seq(chisel3, scalatest, scalacheck)
31 | )
32 |
33 | lazy val hardfloat = (project in file("./third_party/rocket-chip/hardfloat"))
34 | .settings(
35 | commonSettings,
36 | name := "hardfloat"
37 | )
38 |
39 |
40 | lazy val rocketchip = (project in file("./third_party/rocket-chip"))
41 | .dependsOn(hardfloat)
42 | .settings(
43 | commonSettings,
44 | name := "rocket-chip",
45 | addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)
46 | )
47 |
48 | lazy val root = (project in file("."))
49 | .dependsOn(rocketchip)
50 | .settings(
51 | commonSettings,
52 | name := "bottlerocket"
53 | )
54 |
--------------------------------------------------------------------------------
/setup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Copyright 2017 Google LLC
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 | #
17 | # Setup script to parsimoniously clone submodules
18 |
19 | git submodule update --init third_party/rocket-chip
20 | cd third_party/rocket-chip
21 | git submodule update --init --recursive hardfloat
22 | git submodule update --init riscv-tools
23 | cd riscv-tools
24 | git submodule update --init --recursive riscv-tests
25 |
--------------------------------------------------------------------------------
/src/main/scala/bottlerocket/AXI4Lite.scala:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Structural definition of AXI4Lite channel bundles
16 |
17 | package bottlerocket
18 |
19 | import chisel3._
20 | import chisel3.util.Irrevocable
21 | import freechips.rocketchip
22 | import rocketchip.util.GenericParameterizedBundle
23 | import rocketchip.amba.axi4.AXI4BundleParameters
24 |
25 | abstract class AXI4LiteBundleBase(params: AXI4BundleParameters) extends GenericParameterizedBundle(params)
26 |
27 | abstract class AXI4LiteBundleA(params: AXI4BundleParameters) extends AXI4LiteBundleBase(params)
28 | {
29 | val addr = UInt(width = params.addrBits)
30 | val cache = UInt(width = params.cacheBits)
31 | val prot = UInt(width = params.protBits)
32 | }
33 |
34 | class AXI4LiteBundleAW(params: AXI4BundleParameters) extends AXI4LiteBundleA(params)
35 | class AXI4LiteBundleAR(params: AXI4BundleParameters) extends AXI4LiteBundleA(params)
36 |
37 | class AXI4LiteBundleW(params: AXI4BundleParameters) extends AXI4LiteBundleBase(params)
38 | {
39 | val data = UInt(width = params.dataBits)
40 | val strb = UInt(width = params.dataBits/8)
41 | }
42 |
43 | class AXI4LiteBundleR(params: AXI4BundleParameters) extends AXI4LiteBundleBase(params)
44 | {
45 | val data = UInt(width = params.dataBits)
46 | val resp = UInt(width = params.respBits)
47 | }
48 |
49 | class AXI4LiteBundleB(params: AXI4BundleParameters) extends AXI4LiteBundleBase(params)
50 | {
51 | val resp = UInt(width = params.respBits)
52 | }
53 |
54 | class AXI4LiteBundle(params: AXI4BundleParameters) extends AXI4LiteBundleBase(params)
55 | {
56 | val aw = Irrevocable(new AXI4LiteBundleAW(params))
57 | val w = Irrevocable(new AXI4LiteBundleW (params))
58 | val b = Flipped(Irrevocable(new AXI4LiteBundleB (params)))
59 | val ar = Irrevocable(new AXI4LiteBundleAR(params))
60 | val r = Flipped(Irrevocable(new AXI4LiteBundleR (params)))
61 | }
62 |
63 | object AXI4LiteBundle
64 | {
65 | def apply(params: AXI4BundleParameters) = new AXI4LiteBundle(params)
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/scala/bottlerocket/BottleRocketCore.scala:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Top-level pipeline for the BottleRocket core
16 |
17 | package bottlerocket
18 |
19 | import chisel3._
20 | import chisel3.util.{RegEnable}
21 | import chisel3.core.withClock
22 | import freechips.rocketchip._
23 | import rocket._
24 | import devices.debug.DMIIO
25 | import amba.axi4.{AXI4Bundle, AXI4Parameters}
26 | import Params._
27 |
28 | class BottleRocketCore(options: BROptions)(implicit p: config.Parameters) extends Module {
29 | val io = IO(new Bundle {
30 | val constclk = Input(Clock())
31 | val iBus = AXI4LiteBundle(axiParams)
32 | val dBus = AXI4LiteBundle(axiParams)
33 | val nmi = Input(Bool())
34 | val eip = Input(Bool())
35 | val dmi = Flipped(new DMIIO()(p))
36 | val wfisleep = Output(Bool())
37 | val traceInst = Output(UInt(width = xBitwidth))
38 | val traceRetire = Output(Bool())
39 | val traceInterrupt = Output(Bool())
40 | val traceEret = Output(Bool())
41 | val rvfi = new RVFI
42 | })
43 |
44 | /********************
45 | * MAJOR SUBMODULES *
46 | ********************/
47 |
48 | val fetchMgr = Module(new FrontendBuffer(options))
49 | val regfile = new RegfileWithZero(nRegisters, xBitwidth)
50 | val alu = Module(new ALU())
51 | val debug = Module(new DebugModuleFSM())
52 | val csrfile = Module(new CSRFile())
53 | val breakpoints = Module(new BreakpointUnit(csrfile.nBreakpoints))
54 |
55 | /***************
56 | * WFISLEEP FF *
57 | ***************/
58 |
59 | // No need to wait for outstanding IBus request; manager is designed for this case
60 | val s_ready :: s_sleeping :: s_waking :: Nil = chisel3.util.Enum(UInt(), 3)
61 | val sleepstate = withClock(io.constclk) { Reg(init = s_ready) }
62 |
63 | fetchMgr.io.sleeping := sleepstate =/= s_ready
64 | io.wfisleep := sleepstate === s_sleeping && !fetchMgr.io.outstanding
65 |
66 | when (sleepstate === s_ready) {
67 | when (csrfile.io.csr_stall) {
68 | sleepstate := s_sleeping
69 | }
70 | } .elsewhen (sleepstate === s_sleeping) {
71 | when (io.eip) {
72 | sleepstate := s_waking
73 | }
74 | } .otherwise {
75 | when (!csrfile.io.csr_stall) {
76 | sleepstate := s_ready
77 | }
78 | }
79 |
80 | /******************************
81 | * IMPRECISE STORE INTERRUPTS *
82 | ******************************/
83 |
84 | val impreciseStoreInterrupt = Reg(init = Bool(false))
85 |
86 | /*******************************
87 | * HAZARD AND REDIRECT SIGNALS *
88 | *******************************/
89 |
90 | // Hazard and redirect signals
91 | val wait_IF = Wire(Bool())
92 | val stall_IF = Wire(Bool())
93 | val kill_IF = Wire(Bool())
94 | val stall_EX = Wire(Bool())
95 | val kill_EX = Wire(Bool())
96 | val stall_WB = Wire(Bool())
97 | val kill_WB = Wire(Bool())
98 | val exception_WB = Wire(Bool())
99 | val nextPC = Wire(UInt(width = xBitwidth))
100 |
101 | val busReqWait_EX = Wire(Bool())
102 | val mulDivReqWait_EX = Wire(Bool())
103 | val busRespWait_WB = Wire(Bool())
104 | val mulDivRespWait_WB = Wire(Bool())
105 |
106 | // Memory kill signals
107 | val memStructuralHazard = Wire(Bool())
108 | val killMem_EX = Wire(Bool())
109 |
110 | /**********************
111 | * PIPELINE REGISTERS *
112 | **********************/
113 |
114 | val canonicalNOP = UInt(0x13, width = instBitwidth)
115 |
116 | val resetHold = Reg(init = Bool(true))
117 |
118 | val PC_IF = Wire(UInt(width = xBitwidth))
119 |
120 | val PC_EX = Reg(init = UInt(0, width = xBitwidth))
121 | val instPreExp_EX = Reg(init = canonicalNOP)
122 | val pastExceptions_EX = Reg(init = ExceptionCause.clear)
123 | val isBubble_EX = Reg(init = Bool(true))
124 |
125 | val isBubble_WB = Reg(init = Bool(true))
126 | val PC_WB = Reg(init = UInt(0, width = xBitwidth))
127 | val rvc_WB = Reg(init = Bool(false))
128 | val pastExceptions_WB = Reg(init = ExceptionCause.clear)
129 | val jal_WB = Reg(init = Bool(false))
130 | val jalr_WB = Reg(init = Bool(false))
131 | val memEn_WB = Reg(init = Bool(false))
132 | val memAddrOffset_WB = Reg(init = UInt(0, width = xByteOffsetBitwidth))
133 | val isStore_WB = Reg(init = Bool(false))
134 | val memType_WB = Reg(init = UInt(0, width = MT_SZ))
135 | val writeReg_WB = Reg(init = Bool(false))
136 | val rdAddr_WB = Reg(init = UInt(0))
137 | val csrCmd_WB = Reg(init = CSR.N)
138 | val mulDiv_WB = Reg(init = Bool(false))
139 | val aluOut_WB = Reg(init = UInt(0))
140 | val inst_WB = Reg(init = canonicalNOP)
141 |
142 | /***************************
143 | * INSTRUCTION FETCH STAGE *
144 | ***************************/
145 |
146 | PC_IF := fetchMgr.io.resp.bits.pc
147 | val instPreExp_IF = fetchMgr.io.resp.bits.inst
148 | val rvc_IF = instPreExp_IF(1,0) =/= UInt(3)
149 | val exceptions_IF = Wire(new ExceptionCause)
150 | exceptions_IF := ExceptionCause.clear
151 |
152 | fetchMgr.io.req.enter_U_mode := csrfile.io.eret && !csrfile.io.status.debug &&
153 | csrfile.io.status.mpp === UInt(PRV.U)
154 | fetchMgr.io.req.exit_U_mode := csrfile.io.exception && !(csrfile.io.cause === UInt(CSR.debugTriggerCause))
155 | fetchMgr.io.req.pc := nextPC
156 | fetchMgr.io.resp.ready := !stall_IF
157 | io.iBus <> fetchMgr.io.bus
158 |
159 | val busWerr = io.dBus.b.valid && (io.dBus.b.bits.resp === AXI4Parameters.RESP_SLVERR || io.dBus.b.bits.resp === AXI4Parameters.RESP_DECERR)
160 | val werrExceptionTaken = exception_WB && csrfile.io.cause === UInt(Causes.store_access)
161 | when (busWerr) {
162 | impreciseStoreInterrupt := Bool(true)
163 | } .elsewhen(werrExceptionTaken) {
164 | impreciseStoreInterrupt := Bool(false)
165 | }
166 |
167 | exceptions_IF.interrupt := csrfile.io.interrupt
168 | exceptions_IF.storeFault := impreciseStoreInterrupt
169 | exceptions_IF.misalignedFetch := fetchMgr.io.resp.valid && PC_IF(0)
170 | exceptions_IF.illegalFetch := fetchMgr.io.resp.valid && fetchMgr.io.resp.bits.error
171 |
172 | /************************
173 | * DECODE/EXECUTE STAGE *
174 | ************************/
175 |
176 | when (!stall_EX) {
177 | PC_EX := PC_IF
178 | instPreExp_EX := instPreExp_IF
179 | pastExceptions_EX := exceptions_IF
180 | isBubble_EX := kill_IF
181 | }
182 |
183 | val rvc_EX = instPreExp_EX(1,0) =/= UInt(3)
184 | val instExp_EX = new RVCDecoder(instPreExp_EX).decode
185 | val inst_EX = instExp_EX.bits
186 |
187 | val decoder_data = Seq(new MDecode, new IDecode).flatMap(_.table)
188 | val ctrl_EX = Wire(new IntCtrlSigs()).decode(inst_EX, decoder_data)
189 | val memEn_EX = ctrl_EX.mem && (ctrl_EX.mem_cmd === M_XWR || ctrl_EX.mem_cmd === M_XRD)
190 | val isLoad_EX = ctrl_EX.mem && ctrl_EX.mem_cmd === M_XRD
191 | val isStore_EX = ctrl_EX.mem && ctrl_EX.mem_cmd === M_XWR
192 |
193 | val rdAddr_EX = instExp_EX.rd
194 | val rs1Addr_EX = instExp_EX.rs1
195 | val rs2Addr_EX = instExp_EX.rs2
196 | val shamt_EX = inst_EX(24, 20)
197 | val imm_EX = ImmGen(ctrl_EX.sel_imm, inst_EX)
198 |
199 | val csrAccess_EX = (ctrl_EX.csr === CSR.S) || (ctrl_EX.csr === CSR.C) || (ctrl_EX.csr === CSR.W)
200 | val csrRead_EX = rs1Addr_EX === UInt(0) && (ctrl_EX.csr =/= CSR.N)
201 | val csrCmd_EX = Mux(csrRead_EX, CSR.R, ctrl_EX.csr)
202 |
203 | val rs1AddrDebugMuxed_EX = Mux(csrfile.io.status.debug, debug.io.gpraddr, rs1Addr_EX)
204 | val rs1Data_EX = regfile.read(rs1AddrDebugMuxed_EX)
205 | val rs2Data_EX = regfile.read(rs2Addr_EX)
206 |
207 | val rdReady_WB = !(memEn_WB || mulDiv_WB) && (csrCmd_WB === CSR.N)
208 | val writing_WB = !isBubble_WB && writeReg_WB && rdAddr_WB =/= UInt(0)
209 | val rs1RAW_EX = writing_WB && !isBubble_EX && ctrl_EX.rxs1 && rs1Addr_EX === rdAddr_WB
210 | val rs2RAW_EX = writing_WB && !isBubble_EX && ctrl_EX.rxs2 && rs2Addr_EX === rdAddr_WB
211 | val rs1BypassALUResult_EX = rs1RAW_EX && rdReady_WB
212 | val rs2BypassALUResult_EX = rs2RAW_EX && rdReady_WB
213 | val unbypassable_EX = (rs1RAW_EX || rs2RAW_EX) && !rdReady_WB
214 | val rs1DataBypassed_EX = Mux(rs1BypassALUResult_EX,aluOut_WB,rs1Data_EX)
215 | val rs2DataBypassed_EX = Mux(rs2BypassALUResult_EX,aluOut_WB,rs2Data_EX)
216 |
217 | val arg1_EX = Wire(SInt(width = xBitwidth))
218 | when (ctrl_EX.sel_alu1 === A1_RS1) {
219 | arg1_EX := rs1DataBypassed_EX.asSInt
220 | } .elsewhen (ctrl_EX.sel_alu1 === A1_PC) {
221 | arg1_EX := PC_EX.asSInt
222 | } .otherwise {
223 | arg1_EX := SInt(0)
224 | }
225 |
226 | val arg2_EX = Wire(SInt(width = xBitwidth))
227 | when (ctrl_EX.sel_alu2 === A2_RS2) {
228 | arg2_EX := rs2DataBypassed_EX.asSInt
229 | } .elsewhen (ctrl_EX.sel_alu2 === A2_IMM) {
230 | arg2_EX := imm_EX
231 | } .elsewhen (ctrl_EX.sel_alu2 === A2_SIZE) {
232 | arg2_EX := Mux(rvc_EX,SInt(2),SInt(4))
233 | } .otherwise {
234 | arg2_EX := SInt(0)
235 | }
236 |
237 | alu.io.fn := ctrl_EX.alu_fn
238 | alu.io.dw := DW_32
239 | alu.io.in1 := arg1_EX.asUInt
240 | alu.io.in2 := arg2_EX.asUInt
241 |
242 | val memSize_EX = Wire(UInt())
243 | val wdata_EX = Wire(UInt(width = xBitwidth))
244 | when (ctrl_EX.mem_type === MT_B || ctrl_EX.mem_type === MT_BU) {
245 | memSize_EX := UInt(1)
246 | wdata_EX := chisel3.util.Cat(Seq.fill(4){ rs2DataBypassed_EX(7,0) })
247 | } .elsewhen (ctrl_EX.mem_type === MT_H || ctrl_EX.mem_type === MT_HU) {
248 | memSize_EX := UInt(2)
249 | wdata_EX := chisel3.util.Cat(Seq.fill(2){ rs2DataBypassed_EX(15,0) })
250 | } .otherwise {
251 | memSize_EX := UInt(4)
252 | wdata_EX := rs2DataBypassed_EX
253 | }
254 |
255 | csrfile.io.decode.csr := inst_EX(31,20)
256 | val illegalExtension = ctrl_EX.amo || ctrl_EX.fp || ctrl_EX.dp || ctrl_EX.rocc
257 | val illegalCSRAccess = csrfile.io.decode.read_illegal && csrAccess_EX
258 | val illegalCSRWrite = csrfile.io.decode.write_illegal && csrAccess_EX && !csrRead_EX
259 | val illegalSystem = csrfile.io.decode.system_illegal && ((ctrl_EX.mem && ctrl_EX.mem_cmd === M_SFENCE) || (ctrl_EX.csr >= CSR.I))
260 | val illegalInst_EX = !ctrl_EX.legal || illegalExtension || illegalCSRAccess || illegalCSRWrite || illegalSystem
261 | val misaligned_EX = (alu.io.adder_out & (memSize_EX - UInt(1))).orR
262 | val pcBreakpoint = breakpoints.io.xcpt_if
263 | val debugBreakpoint = breakpoints.io.debug_if
264 | val loadBreakpoint = isLoad_EX && breakpoints.io.xcpt_ld
265 | val storeBreakpoint = isStore_EX && breakpoints.io.xcpt_st
266 | val loadDebugBreakpoint = isLoad_EX && breakpoints.io.debug_ld
267 | val storeDebugBreakpoint = isStore_EX && breakpoints.io.debug_st
268 |
269 | val exceptions_EX = Wire(new ExceptionCause)
270 | exceptions_EX := pastExceptions_EX
271 | exceptions_EX.illegalInstruction := illegalInst_EX
272 | exceptions_EX.breakpoint := pcBreakpoint || loadBreakpoint || storeBreakpoint
273 | exceptions_EX.debugBreakpoint := debugBreakpoint || loadDebugBreakpoint || storeDebugBreakpoint
274 | exceptions_EX.loadMisaligned := misaligned_EX && isLoad_EX
275 | exceptions_EX.storeMisaligned := misaligned_EX && isStore_EX
276 |
277 | // Do not access memory with an unhandled exception!
278 | val memEnMasked_EX = memEn_EX && !killMem_EX && !ExceptionCause.toBool(exceptions_EX)
279 | val awSentWUnsent_EX = RegInit(Bool(false))
280 | when (io.dBus.aw.fire && !io.dBus.w.fire) {
281 | awSentWUnsent_EX := Bool(true)
282 | } .elsewhen (io.dBus.w.fire && !io.dBus.aw.fire) {
283 | awSentWUnsent_EX := Bool(false)
284 | }
285 |
286 | io.dBus.ar.valid := memEnMasked_EX && isLoad_EX
287 | io.dBus.ar.bits.addr := alu.io.adder_out.asUInt
288 | io.dBus.ar.bits.cache := AXI4Parameters.CACHE_BUFFERABLE
289 | io.dBus.ar.bits.prot := Mux(csrfile.io.status.prv === UInt(PRV.M), AXI4Parameters.PROT_PRIVILEDGED, AXI4Parameters.PROT_INSECURE)
290 |
291 | io.dBus.aw.valid := memEnMasked_EX && isStore_EX && !awSentWUnsent_EX
292 | io.dBus.aw.bits.addr := alu.io.adder_out.asUInt
293 | io.dBus.aw.bits.cache := AXI4Parameters.CACHE_BUFFERABLE
294 | io.dBus.aw.bits.prot := Mux(csrfile.io.status.prv === UInt(PRV.M), AXI4Parameters.PROT_PRIVILEDGED, AXI4Parameters.PROT_INSECURE)
295 |
296 | io.dBus.w.valid := memEnMasked_EX && isStore_EX
297 | io.dBus.w.bits.data := wdata_EX
298 | io.dBus.w.bits.strb := ((1.U << memSize_EX) - 1.U) << io.dBus.aw.bits.addr(1,0)
299 |
300 | // Multiplier/Divider
301 | val mulDivEnMasked_EX = !kill_EX && ctrl_EX.div
302 | val mulDiv = Module(new MulDiv(cfg = MulDivParams(), width = xBitwidth.get))
303 | mulDiv.io.req.valid := mulDivEnMasked_EX
304 | mulDiv.io.req.bits.dw := ctrl_EX.alu_dw
305 | mulDiv.io.req.bits.fn := ctrl_EX.alu_fn
306 | mulDiv.io.req.bits.in1 := rs1DataBypassed_EX
307 | mulDiv.io.req.bits.in2 := rs2DataBypassed_EX
308 | mulDiv.io.req.bits.tag := rdAddr_EX
309 |
310 | breakpoints.io.pc := PC_EX
311 | breakpoints.io.ea := alu.io.adder_out
312 |
313 | /*******************
314 | * WRITEBACK STAGE *
315 | *******************/
316 |
317 | when (!stall_WB) {
318 | isBubble_WB := kill_EX || busReqWait_EX
319 | PC_WB := PC_EX
320 | rvc_WB := rvc_EX
321 | pastExceptions_WB := exceptions_EX
322 | jal_WB := ctrl_EX.jal
323 | jalr_WB := ctrl_EX.jalr
324 | writeReg_WB := ctrl_EX.wxd
325 | rdAddr_WB := rdAddr_EX
326 | memEn_WB := memEnMasked_EX
327 | memAddrOffset_WB := alu.io.adder_out
328 | isStore_WB := isStore_EX
329 | memType_WB := ctrl_EX.mem_type
330 | csrCmd_WB := ctrl_EX.csr
331 | mulDiv_WB := mulDivEnMasked_EX
332 | aluOut_WB := alu.io.out
333 | inst_WB := inst_EX
334 | }
335 |
336 | val writeRegMasked_WB = !kill_WB && writeReg_WB
337 |
338 | // No exceptions *generated in WB stage* should alter cmd, as they are system-related
339 | val hasPastExceptions = ExceptionCause.toBool(pastExceptions_WB)
340 | val csrCmdMasked_WB = Mux(isBubble_WB || hasPastExceptions, CSR.N, csrCmd_WB)
341 |
342 | val exceptions_WB = Wire(new ExceptionCause)
343 | exceptions_WB := pastExceptions_WB
344 |
345 | val busRerr = io.dBus.b.valid && (io.dBus.b.bits.resp === AXI4Parameters.RESP_SLVERR || io.dBus.b.bits.resp === AXI4Parameters.RESP_DECERR)
346 | val pendingLoadError = memEn_WB && busRerr
347 |
348 | // Load errors are delayed a cycle by stalling the writeback stage to avoid bus-to-bus paths
349 | val delayedLoadError = RegNext(next = pendingLoadError, init = Bool(false))
350 | exceptions_WB.loadFault := delayedLoadError
351 |
352 | // Always ready for bus replies
353 | io.dBus.r.ready := Bool(true)
354 | io.dBus.b.ready := Bool(true)
355 |
356 | // Always ready for mulDiv replies
357 | mulDiv.io.resp.ready := Bool(true)
358 |
359 | // The only time accumulated causes get ignored is with a bubble in the WB stage
360 | exception_WB := ExceptionCause.toBool(exceptions_WB) && !isBubble_WB
361 |
362 | // Only supports a single hart
363 | csrfile.io.hartid := UInt(0)
364 |
365 | // Overwrite CSR cmd/addr/wdata in debug mode
366 | when (csrfile.io.status.debug) {
367 | when (debug.io.debugRet) {
368 | csrfile.io.rw.cmd := CSR.I
369 | csrfile.io.rw.addr := "h7b2".U // dret addr
370 | } .otherwise {
371 | csrfile.io.rw.cmd := Mux(debug.io.csrwrite, CSR.W, CSR.R)
372 | csrfile.io.rw.addr := debug.io.csraddr
373 | }
374 | csrfile.io.rw.wdata := debug.io.regwdata
375 | } .otherwise {
376 | csrfile.io.rw.addr := inst_WB(31, 20)
377 | csrfile.io.rw.cmd := csrCmdMasked_WB
378 | csrfile.io.rw.wdata := aluOut_WB
379 | }
380 |
381 | val busErrCause = csrfile.io.cause === UInt(Causes.store_access) || csrfile.io.cause === UInt(Causes.load_access)
382 | csrfile.io.exception := exception_WB || io.nmi
383 | csrfile.io.retire := !isBubble_WB && !kill_WB
384 | csrfile.io.cause := ExceptionCause.toCause(exceptions_WB, csrfile.io.interrupt_cause)
385 | csrfile.io.pc := PC_WB
386 | csrfile.io.badaddr := aluOut_WB // TODO (amagyar): AXI4 store error address
387 | csrfile.io.fcsr_flags.valid := Bool(false)
388 | csrfile.io.interrupts.meip := io.eip
389 | csrfile.io.interrupts.mtip := Bool(false) // TODO (amagyar): support timer interrupt
390 | csrfile.io.interrupts.msip := Bool(false) // TODO (amagyar): support software interrupt
391 | csrfile.io.interrupts.lip := UInt(0).asTypeOf(csrfile.io.interrupts.lip)
392 | csrfile.io.rocc_interrupt := UInt(0)
393 |
394 | breakpoints.io.status := csrfile.io.status
395 | breakpoints.io.bp := csrfile.io.bp
396 |
397 | val loadExtender = Module(new LoadExtender)
398 | loadExtender.io.offset := memAddrOffset_WB
399 | loadExtender.io.in := io.dBus.r.bits.data
400 | loadExtender.io.memType := memType_WB
401 |
402 | val regWriteData_WB = Wire(UInt(width = xBitwidth))
403 | when (memEn_WB) {
404 | regWriteData_WB := loadExtender.io.out
405 | } .elsewhen (mulDiv_WB) {
406 | regWriteData_WB := mulDiv.io.resp.bits.data
407 | } .elsewhen (csrCmd_WB =/= CSR.N) {
408 | regWriteData_WB := csrfile.io.rw.rdata
409 | } .elsewhen (jalr_WB) {
410 | regWriteData_WB := PC_WB + Mux(rvc_WB,UInt(2),UInt(4))
411 | } .otherwise {
412 | regWriteData_WB := aluOut_WB
413 | }
414 |
415 | /********************
416 | * DEBUG GPR ACCESS *
417 | ********************/
418 |
419 | val regfileWriteData = Mux(csrfile.io.status.debug, debug.io.regwdata, regWriteData_WB)
420 | val regfileWriteAddr = Mux(csrfile.io.status.debug, debug.io.gpraddr, rdAddr_WB)
421 |
422 | when (writeRegMasked_WB || debug.io.gprwrite) {
423 | regfile.write(regfileWriteAddr, regfileWriteData)
424 | }
425 |
426 | /***********
427 | * TRACING *
428 | * *********/
429 |
430 | io.traceEret := csrfile.io.eret
431 | io.traceInterrupt := exception_WB
432 | io.traceRetire := csrfile.io.retire
433 | io.traceInst := inst_WB
434 |
435 | /*****************************
436 | * HAZARD AND REDIRECT LOGIC *
437 | *****************************/
438 |
439 | val readReqWait_EX = io.dBus.ar.valid && !io.dBus.ar.ready
440 | val writeReqWait_EX = (io.dBus.aw.valid && !io.dBus.aw.ready) || (io.dBus.w.valid && !io.dBus.w.ready)
441 | busReqWait_EX := readReqWait_EX || writeReqWait_EX
442 | mulDivReqWait_EX := !isBubble_EX && mulDiv.io.req.valid && !mulDiv.io.req.ready
443 | busRespWait_WB := !isBubble_WB && memEn_WB && ((!isStore_WB && !io.dBus.r.valid) || (isStore_WB && !io.dBus.b.valid))
444 | mulDivRespWait_WB := !isBubble_WB && mulDiv_WB && !mulDiv.io.resp.valid
445 |
446 | wait_IF := Bool(false)
447 | stall_IF := Bool(false)
448 | kill_IF := Bool(false)
449 |
450 | stall_EX := Bool(false)
451 | kill_EX := Bool(false)
452 |
453 | stall_WB := Bool(false)
454 | kill_WB := Bool(false)
455 |
456 | when (isBubble_EX) {
457 | kill_EX := Bool(true)
458 | }
459 |
460 | when (isBubble_WB) {
461 | kill_WB := Bool(true)
462 | }
463 |
464 | val incPC_EX = PC_EX + Mux(rvc_EX, UInt(2), UInt(4))
465 | val targetPC_EX = Wire(UInt(width = xBitwidth))
466 | val redirect_EX = !isBubble_EX && (ctrl_EX.jal || ctrl_EX.jalr || (ctrl_EX.branch && alu.io.cmp_out)) // can eliminate cmp check for constant time
467 | targetPC_EX := incPC_EX
468 | when (ctrl_EX.jalr) {
469 | targetPC_EX := alu.io.out ^ alu.io.out(0)
470 | } .elsewhen(ctrl_EX.jal ||(ctrl_EX.branch && alu.io.cmp_out)) {
471 | targetPC_EX := PC_EX + imm_EX.asUInt
472 | }
473 |
474 | val incAmt_IF = Mux(rvc_IF, UInt(2), UInt(4))
475 | when (io.nmi) {
476 | nextPC := UInt(p(NMI_VEC))
477 | } .elsewhen (exception_WB || csrfile.io.eret) {
478 | nextPC := csrfile.io.evec
479 | } .otherwise {
480 | nextPC := targetPC_EX
481 | }
482 |
483 | fetchMgr.io.req.redirect := exception_WB || io.nmi || csrfile.io.eret || (redirect_EX && !unbypassable_EX)
484 | memStructuralHazard := memEn_EX && !isBubble_EX && memEn_WB && !isBubble_WB
485 | killMem_EX := isBubble_EX || memStructuralHazard || exception_WB || io.nmi || csrfile.io.eret || mulDivRespWait_WB || csrfile.io.csr_stall || unbypassable_EX
486 |
487 | when (csrfile.io.status.debug) {
488 | kill_IF := Bool(true)
489 | kill_EX := Bool(true)
490 | kill_WB := Bool(true)
491 | stall_IF := Bool(true)
492 | } .elsewhen (pendingLoadError) {
493 | stall_IF := Bool(true)
494 | kill_IF := Bool(true)
495 | stall_EX := Bool(true)
496 | kill_EX := Bool(true)
497 | stall_WB := Bool(true)
498 | kill_WB := Bool(true)
499 | } .elsewhen (exception_WB || io.nmi) {
500 | kill_IF := Bool(true)
501 | kill_EX := Bool(true)
502 | kill_WB := Bool(true)
503 | } .elsewhen (csrfile.io.eret) {
504 | kill_IF := Bool(true)
505 | kill_EX := Bool(true)
506 | } .elsewhen (busRespWait_WB || mulDivRespWait_WB || csrfile.io.csr_stall) {
507 | stall_IF := Bool(true)
508 | kill_IF := Bool(true)
509 | stall_EX := Bool(true)
510 | kill_EX := Bool(true)
511 | stall_WB := Bool(true)
512 | kill_WB := Bool(true)
513 | } .elsewhen (memStructuralHazard || unbypassable_EX) {
514 | stall_IF := Bool(true)
515 | kill_IF := Bool(true)
516 | stall_EX := Bool(true)
517 | kill_EX := Bool(true)
518 | } .elsewhen (busReqWait_EX || mulDivReqWait_EX) {
519 | stall_IF := Bool(true)
520 | kill_IF := Bool(true)
521 | stall_EX := Bool(true)
522 | } .elsewhen (redirect_EX) {
523 | kill_IF := Bool(true)
524 | } .elsewhen (!fetchMgr.io.resp.valid) {
525 | kill_IF := Bool(true)
526 | wait_IF := Bool(true)
527 | }
528 |
529 | /*********
530 | * DEBUG *
531 | *********/
532 |
533 | val singleStepped = Reg(init = Bool(false))
534 | val issuing_IF = !(kill_IF || wait_IF)
535 | val issued = !(isBubble_EX && isBubble_WB)
536 | when (csrfile.io.singleStep && (issuing_IF || issued)) {
537 | singleStepped := Bool(true)
538 | } .elsewhen (csrfile.io.status.debug) {
539 | singleStepped := Bool(false)
540 | }
541 |
542 | debug.io.singleStepHalt := csrfile.io.status.debug && singleStepped
543 | debug.io.debugModeActive := csrfile.io.status.debug
544 | debug.io.csrrdata := csrfile.io.rw.rdata
545 | debug.io.gprrdata := rs1Data_EX
546 | csrfile.io.interrupts.debug := debug.io.debugInt || singleStepped
547 | when (singleStepped) {
548 | exceptions_IF.interrupt := Bool(true)
549 | }
550 |
551 | debug.io.dmi <> io.dmi
552 |
553 | /********
554 | * RVFI *
555 | ********/
556 |
557 | // pipeline some otherwise unnecessary signals to WB stage
558 | val rvfi_rs1Addr_WB = RegEnable(rs1Addr_EX, !stall_WB)
559 | val rvfi_rs1Data_WB = RegEnable(rs1DataBypassed_EX, !stall_WB)
560 | val rvfi_rs2Addr_WB = RegEnable(rs2Addr_EX, !stall_WB)
561 | val rvfi_rs2Data_WB = RegEnable(rs2DataBypassed_EX, !stall_WB)
562 | val rvfi_nextPC_WB_from_EX = RegEnable(targetPC_EX, !stall_WB)
563 | val rvfi_store_data_WB = RegEnable(wdata_EX, !stall_WB)
564 | val rvfi_retire = csrfile.io.retire === UInt(1)
565 | val rvfi_order = Reg(init = UInt(0, 64.W))
566 | when (rvfi_retire) {
567 | rvfi_order := rvfi_order + UInt(1)
568 | }
569 |
570 | val rvfi_next_starts_handler = Reg(init = Bool(false))
571 | when (exception_WB) {
572 | rvfi_next_starts_handler := Bool(true)
573 | } .elsewhen (rvfi_retire) {
574 | rvfi_next_starts_handler := Bool(false)
575 | }
576 |
577 | val rvfi_mem_size_mask = Wire(UInt())
578 | when (memEn_WB) {
579 | when (memType_WB === MT_B || memType_WB === MT_BU) {
580 | rvfi_mem_size_mask := UInt(1)
581 | } .elsewhen (memType_WB === MT_H || memType_WB === MT_HU) {
582 | rvfi_mem_size_mask := UInt(3)
583 | } .otherwise {
584 | rvfi_mem_size_mask := UInt(15)
585 | }
586 | } .otherwise {
587 | rvfi_mem_size_mask := UInt(0)
588 | }
589 |
590 | io.rvfi.valid := rvfi_retire
591 | io.rvfi.order := rvfi_order
592 | io.rvfi.insn := inst_WB
593 | io.rvfi.trap := exception_WB && (exceptions_WB.illegalInstruction || exceptions_WB.loadMisaligned || exceptions_WB.storeMisaligned)
594 | io.rvfi.halt := Bool(false) // TODO (amagyar): clarify halt meaning
595 | io.rvfi.intr := rvfi_next_starts_handler
596 | io.rvfi.rs1_addr := rvfi_rs1Addr_WB
597 | io.rvfi.rs1_rdata := rvfi_rs1Data_WB
598 | io.rvfi.rs2_addr := rvfi_rs2Addr_WB
599 | io.rvfi.rs2_rdata := rvfi_rs2Data_WB
600 | io.rvfi.rd_addr := Mux((writeRegMasked_WB || debug.io.gprwrite), regfileWriteAddr, UInt(0))
601 | io.rvfi.rd_wdata := Mux((writeRegMasked_WB || debug.io.gprwrite), regfileWriteData, UInt(0))
602 | io.rvfi.pc_rdata := PC_WB
603 | io.rvfi.pc_wdata := Mux(exception_WB || csrfile.io.eret || io.nmi, nextPC, rvfi_nextPC_WB_from_EX)
604 | io.rvfi.mem_addr := aluOut_WB
605 | io.rvfi.mem_rmask := Mux(memEn_WB && !isStore_WB, rvfi_mem_size_mask, UInt(0))
606 | io.rvfi.mem_rdata := Mux(memEn_WB && !isStore_WB, regfileWriteData, UInt(0))
607 | io.rvfi.mem_wmask := Mux(memEn_WB && isStore_WB, rvfi_mem_size_mask, UInt(0))
608 | io.rvfi.mem_wdata := Mux(memEn_WB && isStore_WB, rvfi_store_data_WB, UInt(0))
609 |
610 | }
611 |
--------------------------------------------------------------------------------
/src/main/scala/bottlerocket/BottleRocketGenerator.scala:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Generator for emitting Verilog
16 |
17 | package bottlerocket
18 |
19 | import chisel3._
20 | import firrtl.{ExecutionOptionsManager, HasFirrtlOptions, CommonOptions, FirrtlExecutionOptions, ComposableOptions}
21 |
22 | case class BROptions(nProgInterrupts: Int = 240, resetVec: BigInt = BigInt("100", 16)) extends ComposableOptions
23 |
24 | object BottleRocketGenerator extends App {
25 | val config = new DefaultBottleRocketConfig
26 |
27 | trait HasBROptions {
28 | self: ExecutionOptionsManager =>
29 | var brOptions = BROptions()
30 | parser.note("BottleRocket options")
31 | parser.opt[Int]("nProgInterrupts")
32 | .abbr("nInts")
33 | .valueName("")
34 | .foreach { n => brOptions = brOptions.copy(nProgInterrupts = n) }
35 | parser.opt[String]("reset-vec")
36 | .abbr("rstVec")
37 | .valueName("")
38 | .foreach { str => brOptions = brOptions.copy(resetVec = BigInt(str, 16)) }
39 | }
40 |
41 | val optionsManager = new ExecutionOptionsManager("chisel3")
42 | with HasChiselExecutionOptions
43 | with HasFirrtlOptions
44 | with HasBROptions { }
45 |
46 | if (optionsManager.parse(args)) {
47 | Driver.execute(optionsManager, () => new BottleRocketCore(optionsManager.brOptions)(config))
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/scala/bottlerocket/DebugModuleFSM.scala:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Debug Module that controls top-level behaviors of SiFive debug spec v0.13
16 |
17 | package bottlerocket
18 |
19 | import chisel3._
20 | import chisel3.util.{Enum, Cat, Queue}
21 | import freechips.rocketchip._
22 | import devices.debug.{DMIReq, DMIResp, DMIIO, DMIConsts, DebugModuleParams}
23 | import Params._
24 |
25 | class DebugModuleFSM()(implicit p: config.Parameters) extends Module {
26 | val io = IO(new Bundle {
27 | val singleStepHalt = Input(Bool())
28 | val debugInt = Output(Bool())
29 | val debugRet = Output(Bool())
30 | val debugModeActive = Input(Bool())
31 | val gpraddr = Output(UInt(width = 5.W))
32 | val csraddr = Output(UInt(width = 12.W))
33 | val gprwrite = Output(Bool())
34 | val csrwrite = Output(Bool())
35 | val gprrdata = Input(UInt(width = xBitwidth))
36 | val csrrdata = Input(UInt(width = xBitwidth))
37 | val regwdata = Output(UInt(width = xBitwidth))
38 | val dmi = Flipped(new DMIIO()(p))
39 | })
40 |
41 | val reqQueue = Module(new Queue(new DMIReq(p(DebugModuleParams).nDMIAddrSize), 2))
42 | val respQueue = Module(new Queue(new DMIResp(), 2))
43 |
44 | reqQueue.io.enq <> io.dmi.req
45 | reqQueue.io.deq.ready := respQueue.io.enq.ready
46 |
47 | val dmiReqData = reqQueue.io.deq.bits.data
48 | val dmiReqAddr = reqQueue.io.deq.bits.addr
49 | val dmiReadActive = reqQueue.io.deq.fire && reqQueue.io.deq.bits.op === DMIConsts.dmi_OP_READ
50 | val dmiWriteActive = reqQueue.io.deq.fire && reqQueue.io.deq.bits.op === DMIConsts.dmi_OP_WRITE
51 | val dmiRespValid = Reg(init = Bool(false))
52 | val dmiRespType = Reg(init = DMIConsts.dmi_RESP_SUCCESS)
53 | val dmiRespData = Reg(UInt())
54 |
55 | dmiRespValid := reqQueue.io.deq.fire
56 | respQueue.io.enq.valid := dmiRespValid
57 | respQueue.io.enq.bits.resp := dmiRespType
58 | respQueue.io.enq.bits.data := dmiRespData
59 | io.dmi.resp <> respQueue.io.deq
60 |
61 |
62 | def zPad(w: Int) = UInt(0, width = w.W)
63 |
64 | val s_running :: s_halting :: s_triggering :: s_halted :: s_resuming :: Nil = chisel3.util.Enum(UInt(), 5)
65 | val haltState = Reg(init = s_running)
66 |
67 | val s_idle :: s_busy :: s_error :: Nil = chisel3.util.Enum(UInt(), 3)
68 | val cmdState = Reg(init = s_idle)
69 |
70 | // abstract data registers
71 | val data0 = Reg(init = zPad(32))
72 |
73 | // dmcontrol fields
74 | val haltReq = Reg(init = Bool(false))
75 | val resumeReq = Reg(init = Bool(false))
76 | val dmActive = Bool(true)
77 |
78 | // dmstatus fields
79 | val running = (haltState === s_running)
80 | val halted = (haltState === s_halted)
81 | val resumeAck = Reg(init = Bool(false))
82 | val version = UInt(2, width = 4.W)
83 |
84 | // abstractcs fields
85 | val progsize = zPad(5)
86 | val cmdBusy = (cmdState === s_busy)
87 | val cmdErr = Reg(init = zPad(3))
88 | val datacount = UInt(1, width = 5.W)
89 |
90 | // abstract cmd
91 | val abstractCmd = Reg(init = zPad(32))
92 |
93 | // read mapping
94 | dmiRespType := DMIConsts.dmi_RESP_SUCCESS
95 | when (dmiReqAddr === "h04".U) {
96 | dmiRespData := data0
97 | } .elsewhen (dmiReqAddr === "h10".U) {
98 | dmiRespData := Cat(haltReq, resumeReq, zPad(29), dmActive)
99 | } .elsewhen (dmiReqAddr === "h11".U) {
100 | dmiRespData := Cat(zPad(14), resumeAck, resumeAck, zPad(4), running, running, halted, halted, zPad(4), version)
101 | } .elsewhen (dmiReqAddr === "h16".U) {
102 | dmiRespData := Cat(zPad(3), progsize, zPad(11), cmdBusy, zPad(1), cmdErr, zPad(3), datacount)
103 | } .elsewhen (dmiReqAddr === "h17".U) {
104 | dmiRespData := abstractCmd
105 | } .otherwise {
106 | dmiRespType := DMIConsts.dmi_RESP_FAILURE
107 | dmiRespData := zPad(32)
108 | }
109 |
110 | val cmdType = abstractCmd(31,24)
111 | val newCmd = dmiWriteActive && (dmiReqAddr === "h17".U)
112 | val writeInCmd = (cmdState === s_busy) && dmiWriteActive
113 | val clearErr = dmiWriteActive && (dmiReqAddr === "h16".U) && dmiReqData(10,8).orR
114 | val invalidCmd = abstractCmd(31,24) =/= UInt(0)
115 | val isGPR = abstractCmd(15,5) === UInt(0x1000, width = 16)(15,5)
116 | val isCSR = abstractCmd(15,12) === UInt(0)
117 | val doRegAccess = (haltState === s_halted) && (cmdState === s_busy) && (cmdType === UInt(0)) && abstractCmd(17)
118 | val doRegWrite = doRegAccess && abstractCmd(16)
119 | val doRegRead = doRegAccess && !abstractCmd(16)
120 |
121 | // write mapping (except cmderr)
122 | when (dmiWriteActive) {
123 | when (dmiReqAddr === "h04".U) {
124 | data0 := dmiReqData
125 | } .elsewhen (dmiReqAddr === "h10".U) {
126 | haltReq := dmiReqData(31)
127 | resumeReq := dmiReqData(30)
128 | resumeAck := Bool(false)
129 | } .elsewhen (dmiReqAddr === "h17".U) {
130 | abstractCmd := dmiReqData
131 | }
132 | } .elsewhen (doRegRead) {
133 | data0 := Mux(isGPR, io.gprrdata, io.csrrdata)
134 | }
135 |
136 | val nextCmdState = Wire(UInt())
137 | nextCmdState := cmdState
138 | when (cmdState === s_idle) {
139 | when (newCmd) {
140 | nextCmdState := s_busy
141 | }
142 | } .elsewhen (cmdState === s_busy) {
143 | when (writeInCmd || invalidCmd || !halted) {
144 | nextCmdState := s_error
145 | } .otherwise {
146 | nextCmdState := s_idle
147 | }
148 | } .otherwise {
149 | nextCmdState := Mux(clearErr, s_idle, s_error)
150 | }
151 | cmdState := nextCmdState
152 |
153 | when (nextCmdState === s_error) {
154 | when (!writeInCmd) {
155 | cmdErr := UInt(1)
156 | } .elsewhen (!halted) {
157 | cmdErr := UInt(4)
158 | } .otherwise {
159 | cmdErr := UInt(2)
160 | }
161 | }
162 |
163 | // This signal ensures that each resume request causes only ONE resume
164 | val freshResumeReq = resumeReq && !resumeAck
165 |
166 | val nextHaltState = Wire(UInt())
167 | nextHaltState := haltState
168 | when (haltState === s_running) {
169 | when (io.singleStepHalt) {
170 | nextHaltState := s_halted
171 | } .elsewhen (haltReq) {
172 | nextHaltState := s_halting
173 | } .elsewhen (io.debugModeActive) {
174 | nextHaltState := s_halted // triggering
175 | }
176 | } .elsewhen (haltState === s_halting) {
177 | when (io.debugModeActive) {
178 | nextHaltState := s_halted
179 | }
180 | } .elsewhen (haltState === s_halted) {
181 | when (freshResumeReq) {
182 | nextHaltState := s_resuming
183 | }
184 | } .otherwise {
185 | when (!io.debugModeActive) {
186 | nextHaltState := s_running
187 | resumeAck := Bool(true)
188 | }
189 | }
190 | haltState := nextHaltState
191 |
192 | io.debugInt := haltState === s_halting
193 | io.debugRet := haltState === s_halted && nextHaltState === s_resuming
194 | io.gpraddr := abstractCmd(4,0)
195 | io.csraddr := abstractCmd(11,0)
196 | io.gprwrite := isGPR && doRegWrite
197 | io.csrwrite := isCSR && doRegWrite
198 | io.regwdata := data0
199 | }
200 |
--------------------------------------------------------------------------------
/src/main/scala/bottlerocket/DebugStepper.scala:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Debug stimulus generator that single steps the core continuously
16 |
17 | package bottlerocket
18 |
19 | import chisel3._
20 | import chisel3.util.{Enum,Cat}
21 | import freechips.rocketchip._
22 | import devices.debug.{DMIReq, DMIResp, DMIIO, DMIConsts}
23 | import Params._
24 |
25 | class DebugStepper()(implicit p: config.Parameters) extends Module {
26 | val io = IO(new Bundle {
27 | val dmi = new DMIIO()(p)
28 | })
29 |
30 | // running: wait for halted to be set
31 | // halted: set resumereq
32 | // resuming: wait for resumeack
33 |
34 | val s_waitForHalt :: s_restart :: s_waitForResume :: Nil = chisel3.util.Enum(UInt(), 3)
35 | val haltState = Reg(init = s_waitForHalt)
36 |
37 | val nextHaltState = Wire(UInt())
38 | nextHaltState := haltState
39 |
40 | io.dmi.req.valid := Bool(true)
41 | io.dmi.resp.ready := Bool(true)
42 | io.dmi.req.bits.addr := Mux(haltState === s_restart, "h10".U, "h11".U)
43 | io.dmi.req.bits.data := "h40000001".U
44 | io.dmi.req.bits.op := Mux(haltState === s_restart, DMIConsts.dmi_OP_WRITE, DMIConsts.dmi_OP_READ)
45 |
46 | when (haltState === s_waitForHalt) {
47 | when (io.dmi.resp.fire && io.dmi.resp.bits.data(8)) {
48 | haltState := s_restart
49 | }
50 | } .elsewhen (haltState === s_restart) {
51 | when (io.dmi.req.fire) {
52 | haltState := s_waitForResume
53 | }
54 | } .otherwise {
55 | when (io.dmi.resp.fire && io.dmi.resp.bits.data(16)) {
56 | haltState := s_waitForHalt
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/scala/bottlerocket/ExceptionCause.scala:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Exception / interrupt cause encodings
16 |
17 | package bottlerocket
18 |
19 | import chisel3._
20 | import chisel3.util.MuxCase
21 | import freechips.rocketchip.rocket.{CSR, Causes}
22 |
23 | class ExceptionCause extends Bundle {
24 | val misalignedFetch = Bool()
25 | val illegalFetch = Bool()
26 | val illegalInstruction = Bool()
27 | val breakpoint = Bool()
28 | val debugBreakpoint = Bool()
29 | val loadMisaligned = Bool()
30 | val loadFault = Bool()
31 | val storeMisaligned = Bool()
32 | val storeFault = Bool()
33 | val interrupt = Bool()
34 | }
35 |
36 | object ExceptionCause {
37 | def clear: ExceptionCause = 0.U.asTypeOf(new ExceptionCause)
38 |
39 | def toBool(e: ExceptionCause): Bool = e.asUInt.orR
40 |
41 | def toCause(eCause: ExceptionCause, iCause: UInt): UInt = {
42 | MuxCase(iCause, Seq(
43 | (eCause.misalignedFetch, UInt(Causes.misaligned_fetch)),
44 | (eCause.illegalFetch, UInt(Causes.fetch_access)),
45 | (eCause.illegalInstruction, UInt(Causes.illegal_instruction)),
46 | (eCause.breakpoint, UInt(Causes.breakpoint)),
47 | (eCause.debugBreakpoint, UInt(CSR.debugTriggerCause)),
48 | (eCause.loadMisaligned, UInt(Causes.misaligned_load)),
49 | (eCause.loadFault, UInt(Causes.load_access)),
50 | (eCause.storeMisaligned, UInt(Causes.misaligned_store)),
51 | (eCause.storeFault, UInt(Causes.store_access))))
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/scala/bottlerocket/FrontendBuffer.scala:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Decoupled frontend implementation with efficient misaligned 32-bit fetch
16 |
17 | package bottlerocket
18 |
19 | import chisel3._
20 | import chisel3.core.withClock
21 | import chisel3.util.{Decoupled,Valid,Cat}
22 | import freechips.rocketchip.amba.axi4.{AXI4Parameters}
23 | import Params._
24 |
25 | class FrontendReq extends Bundle {
26 | val pc = Input(UInt(xBitwidth))
27 | val redirect = Input(Bool())
28 | val enter_U_mode = Input(Bool())
29 | val exit_U_mode = Input(Bool())
30 | }
31 |
32 | class FrontendResp extends Bundle {
33 | val pc = Output(UInt(xBitwidth))
34 | val inst = Output(UInt(instBitwidth))
35 | val error = Output(Bool())
36 | }
37 |
38 | class FrontendBuffer(options: BROptions) extends Module {
39 |
40 | val io = IO(new Bundle{
41 | val outstanding = Output(Bool())
42 | val sleeping = Input(Bool())
43 | val req = new FrontendReq
44 | val resp = Decoupled(new FrontendResp)
45 | val bus = AXI4LiteBundle(axiParams)
46 | })
47 |
48 | def wordAddress(x: UInt) = x & ~UInt(3, width = xBitwidth)
49 | def isRVC(i: UInt) = i(1,0) =/= UInt(3)
50 | def isWordAligned(a: UInt) = a(1,0) === UInt(0)
51 | def min(a: UInt, b: UInt) = Mux(a < b, a, b)
52 |
53 | // Hold reqvalid low during sleep
54 | val reqvalid_ungated = Wire(Bool())
55 | io.bus.ar.valid := reqvalid_ungated && !io.sleeping
56 |
57 | // These two registers track issued bus requests -> must be gated with bus clock, if different
58 | val n_pending = Reg(UInt(3.W), init = UInt(0))
59 | val last_req_addr = Reg(UInt(xBitwidth))
60 | io.outstanding := n_pending =/= UInt(0)
61 |
62 | val n_to_drop = Reg(UInt(3.W), init = UInt(0))
63 | val true_pending = n_pending - n_to_drop
64 |
65 | val buf_vec = Reg(Vec(4, UInt(16.W)))
66 | val err_vec = Reg(Vec(4, Bool()))
67 | val buf_base = Reg(UInt(xBitwidth), init = UInt(options.resetVec))
68 | val buf_size = Reg(UInt(4.W), init = UInt(0)) // SIZE IS IN BYTES
69 | val buf_head = Reg(UInt(2.W), init = UInt(0)) // PTRS ARE HALFWORD INDICES
70 | val buf_tail = Reg(UInt(2.W), init = UInt(0)) // PTRS ARE HALFWORD INDICES
71 | val buffer_full = (buf_size + (true_pending << 2)) > UInt(4) || n_pending === UInt(7)
72 |
73 | val clear_buffer = Wire(Bool())
74 | val drop_outstanding = Wire(Bool())
75 | val expected_bus_fetch_valid = io.bus.r.valid && n_to_drop === UInt(0)
76 |
77 | val head_halfword = buf_vec(buf_head)
78 | val next_halfword = buf_vec(buf_head + UInt(1))
79 | val jumped_to_halfword_aligned = Reg(init = Bool(false))
80 | val n_useful_bus_bytes = Mux(jumped_to_halfword_aligned, UInt(2), UInt(4))
81 | val bus_first_halfword = Mux(jumped_to_halfword_aligned, io.bus.r.bits.data(31,16), io.bus.r.bits.data(15,0))
82 | val bus_second_halfword = Mux(jumped_to_halfword_aligned, io.bus.r.bits.data(15,0), io.bus.r.bits.data(31,16))
83 |
84 | val hold_reset = Reg(init = Bool(true))
85 | hold_reset := Bool(false)
86 |
87 | // constant AXI4Lite fields
88 | io.bus.ar.bits.cache := AXI4Parameters.CACHE_BUFFERABLE
89 | io.bus.r.ready := Bool(true)
90 |
91 | // zero write channel signals
92 | io.bus.aw.valid := false.B
93 | io.bus.aw.bits.addr := 0.U
94 | io.bus.aw.bits.cache := 0.U
95 | io.bus.aw.bits.prot := 0.U
96 | io.bus.w.valid := false.B
97 | io.bus.w.bits.data := 0.U
98 | io.bus.w.bits.strb := 0.U
99 | io.bus.b.ready := true.B
100 |
101 | // Sometimes redirects go to halfword-aligned addresses
102 | when (io.req.redirect) {
103 | jumped_to_halfword_aligned := !isWordAligned(io.req.pc)
104 | } .elsewhen (expected_bus_fetch_valid) {
105 | jumped_to_halfword_aligned := Bool(false)
106 | }
107 |
108 | // Record last requested address
109 | when (io.bus.ar.ready && io.bus.ar.valid) {
110 | last_req_addr := io.bus.ar.bits.addr
111 | }
112 |
113 | // Privilege modes
114 | val bus_prot = Reg(init = AXI4Parameters.PROT_PRIVILEDGED)
115 | when (io.req.enter_U_mode) {
116 | bus_prot := AXI4Parameters.PROT_INSTRUCTION
117 | } .elsewhen (io.req.exit_U_mode) {
118 | bus_prot := AXI4Parameters.PROT_PRIVILEDGED
119 | }
120 | io.bus.ar.bits.prot := bus_prot
121 |
122 | // two main behaviors: branch/jump/exception/etc or sequential code
123 | // ALL privilege level changes are also redirects, so this handles flushing
124 | when (hold_reset) {
125 | reqvalid_ungated := Bool(false)
126 | io.bus.ar.bits.addr := wordAddress(io.req.pc)
127 | clear_buffer := Bool(false)
128 | drop_outstanding := Bool(false)
129 | } .elsewhen (io.req.redirect) {
130 | reqvalid_ungated := Bool(true)
131 | io.bus.ar.bits.addr := wordAddress(io.req.pc)
132 | clear_buffer := Bool(true)
133 | drop_outstanding := Bool(true)
134 | } .otherwise {
135 | reqvalid_ungated := !buffer_full
136 | io.bus.ar.bits.addr := Mux(true_pending > UInt(0), last_req_addr + UInt(4), wordAddress(buf_base + buf_size))
137 | clear_buffer := Bool(false)
138 | drop_outstanding := Bool(false)
139 | }
140 |
141 | // outstanding / to-drop transaction counters
142 | // Never more than one USEFUL outstanding transaction!
143 | val n_pending_next = n_pending +
144 | Mux(io.bus.ar.ready && io.bus.ar.valid, UInt(1), UInt(0)) -
145 | Mux(io.bus.r.valid, UInt(1), UInt(0))
146 | n_pending := n_pending_next
147 | when (drop_outstanding) {
148 | n_to_drop := n_pending - Mux(io.bus.r.valid, UInt(1), UInt(0))
149 | } .elsewhen (n_to_drop =/= UInt(0) && io.bus.r.valid) {
150 | n_to_drop := n_to_drop - UInt(1)
151 | }
152 |
153 | // buffer control path
154 | when (clear_buffer) {
155 | buf_size := UInt(0)
156 | buf_base := io.req.pc
157 | buf_tail := UInt(0)
158 | buf_head := UInt(0)
159 | } .otherwise {
160 | val resp_inst_size = Mux(isRVC(io.resp.bits.inst), UInt(2), UInt(4))
161 | val base_diff_bytes = Mux(io.resp.fire, resp_inst_size, UInt(0))
162 | val end_diff_bytes = Mux(expected_bus_fetch_valid, n_useful_bus_bytes, UInt(0))
163 | val head_diff = base_diff_bytes >> 1
164 | val tail_diff = end_diff_bytes >> 1
165 | buf_head := buf_head + head_diff
166 | buf_base := buf_base + base_diff_bytes
167 | buf_tail := buf_tail + tail_diff
168 | buf_size := min(buf_size + end_diff_bytes - base_diff_bytes, UInt(8))
169 | }
170 |
171 | val busHasError = io.bus.r.valid && (io.bus.r.bits.resp === AXI4Parameters.RESP_SLVERR || io.bus.r.bits.resp === AXI4Parameters.RESP_DECERR)
172 | // buffer refill writes:
173 | // All replies are already filtered with 'expected_bus_fetch_valid'
174 | // Therefore, when bus reply appears, take it!
175 | when (expected_bus_fetch_valid) {
176 | buf_vec(buf_tail) := bus_first_halfword
177 | // Second half is only undesired after a branch
178 | // In this case, all buffer contents are garbage, so writing wastefully is fine
179 | buf_vec(buf_tail + UInt(1)) := bus_second_halfword
180 | err_vec(buf_tail) := busHasError
181 | err_vec(buf_tail + UInt(1)) := busHasError
182 | }
183 |
184 | // reply management
185 | io.resp.bits.pc := buf_base
186 | when (buf_size === UInt(0)) {
187 | io.resp.valid := expected_bus_fetch_valid && (!jumped_to_halfword_aligned || isRVC(bus_first_halfword))
188 | io.resp.bits.inst := Cat(bus_second_halfword, bus_first_halfword)
189 | io.resp.bits.error := busHasError
190 | } .elsewhen (buf_size === UInt(2) && !isRVC(buf_vec(buf_head))) {
191 | io.resp.valid := expected_bus_fetch_valid
192 | io.resp.bits.inst := Cat(bus_first_halfword, head_halfword)
193 | io.resp.bits.error := busHasError || err_vec(buf_head)
194 | } .otherwise {
195 | io.resp.valid := Bool(true)
196 | io.resp.bits.inst := Cat(next_halfword, head_halfword)
197 | io.resp.bits.error := err_vec(buf_head) || err_vec(buf_head + UInt(1))
198 | }
199 |
200 | }
201 |
--------------------------------------------------------------------------------
/src/main/scala/bottlerocket/LoadExtender.scala:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Load data extender
16 |
17 | package bottlerocket
18 |
19 | import chisel3._
20 | import chisel3.util.Cat
21 | import freechips.rocketchip._
22 | import rocket._
23 | import Params._
24 |
25 | class LoadExtender extends Module {
26 | val io = IO(new Bundle {
27 | val offset = Input(UInt(width = xByteOffsetBitwidth))
28 | val in = Input(UInt(width = xBitwidth))
29 | val memType = Input(UInt(width = MT_SZ))
30 | val out = Output(UInt(width = xBitwidth))
31 | })
32 |
33 | val outSigned = Wire(SInt(width = xBitwidth))
34 |
35 | val inByteSwizzled = Mux(io.offset(0),
36 | Cat(io.in(23,16), io.in(31,24), io.in(7,0), io.in(15,8)),
37 | io.in)
38 |
39 | val inSwizzled = Mux(io.offset(1),
40 | Cat(inByteSwizzled(15,0), inByteSwizzled(31,16)),
41 | inByteSwizzled)
42 |
43 | outSigned := inSwizzled.asSInt
44 | io.out := outSigned.asUInt
45 |
46 | when (io.memType === MT_B) {
47 | outSigned := inSwizzled(7,0).asSInt
48 | } .elsewhen(io.memType === MT_H) {
49 | outSigned := inSwizzled(15,0).asSInt
50 | } .elsewhen(io.memType === MT_BU) {
51 | io.out := inSwizzled(7,0)
52 | } .elsewhen(io.memType === MT_HU) {
53 | io.out := inSwizzled(15,0)
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/scala/bottlerocket/Params.scala:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // BottleRocket parameters
16 |
17 | package bottlerocket
18 |
19 | import chisel3._
20 | import chisel3.internal.firrtl.Width
21 | import freechips.rocketchip._
22 | import config.{Config, Field}
23 | import system.TinyConfig
24 | import rocket.{RocketCoreParams, MulDivParams, DCacheParams, ICacheParams}
25 | import amba.axi4.{AXI4BundleParameters}
26 | import tile._
27 | import coreplex._
28 | import devices.debug.{DebugModuleParams, DefaultDebugModuleParams}
29 |
30 | package object Params {
31 | val busAddrBitwidth = 32.W
32 | val busSizeBitwidth = 2.W
33 | val busLenBitwidth = 4.W
34 | val busDataBitwidth = 32.W
35 | val busUserBitwidth = 16.W
36 | val busIDBitwidth = 16.W
37 |
38 | val xBitwidth = 32.W
39 | val halfXBitwidth = 16.W
40 | val xByteOffsetBitwidth = 2.W
41 | val instBitwidth = 32.W
42 | val nRegisters = 32
43 | val axiParams = new AXI4BundleParameters(32, 32, 16, 16)
44 | }
45 |
46 | case object NMI_VEC extends Field[BigInt]
47 |
48 | class TileConfig extends Config((site, here, up) => {
49 | case TileKey => RocketTileParams(
50 | core = RocketCoreParams(
51 | useUser = true,
52 | useVM = false,
53 | useAtomics = false,
54 | nBreakpoints = 4,
55 | nPMPs = 0,
56 | fpu = None,
57 | mulDiv = Some(MulDivParams(mulUnroll = 8))),
58 | btb = None,
59 | dcache = Some(DCacheParams()),
60 | icache = Some(ICacheParams()))
61 | case BuildRoCC => false
62 | case DebugModuleParams => DefaultDebugModuleParams(site(XLen))
63 | case NMI_VEC => BigInt("100", 16)
64 | })
65 |
66 | class DefaultBottleRocketConfig extends Config(new TileConfig ++ new TinyConfig)
67 |
--------------------------------------------------------------------------------
/src/main/scala/bottlerocket/RVFI.scala:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Chisel Bundle implementation of RISC-V Formal Interface (RVFI)
16 |
17 | package bottlerocket
18 |
19 | import chisel3._
20 | import Params._
21 |
22 | class RVFI extends Bundle {
23 | val valid = Output(Bool())
24 | val order = Output(UInt(64.W))
25 | val insn = Output(UInt(32.W))
26 | val trap = Output(Bool())
27 | val halt = Output(Bool())
28 | val intr = Output(Bool())
29 | val rs1_addr = Output(UInt(5.W))
30 | val rs1_rdata = Output(UInt(xBitwidth))
31 | val rs2_addr = Output(UInt(5.W))
32 | val rs2_rdata = Output(UInt(xBitwidth))
33 | val rd_addr = Output(UInt(5.W))
34 | val rd_wdata = Output(UInt(xBitwidth))
35 | val pc_rdata = Output(UInt(xBitwidth))
36 | val pc_wdata = Output(UInt(xBitwidth))
37 | val mem_addr = Output(UInt(xBitwidth))
38 | val mem_rmask = Output(UInt(4.W))
39 | val mem_wmask = Output(UInt(4.W))
40 | val mem_rdata = Output(UInt(xBitwidth))
41 | val mem_wdata = Output(UInt(xBitwidth))
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/scala/bottlerocket/RegfileWithZero.scala:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // This flop-based regfile has register number zero hardwired to zero
16 |
17 | package bottlerocket
18 |
19 | import chisel3._
20 | import chisel3.util._
21 | import Params._
22 | import chisel3.internal.firrtl.Width
23 |
24 | class RegfileWithZero(nRegs: Int, regWidth: Width, name: String = "regfileReverseIdx") {
25 | // nRegs must be positive power of two
26 | Predef.assert(nRegs > 0)
27 | Predef.assert((nRegs & (nRegs - 1)) == 0)
28 | private val idxMSB = log2Ceil(nRegs) - 1
29 | private val regs = Mem(nRegs-1, UInt(width = regWidth))
30 | regs.suggestName(name)
31 | private def toIndex(addr: UInt) = ~addr(idxMSB,0)
32 | def read(addr: UInt) = Mux(addr === 0.U, 0.U, regs.read(toIndex(addr)))
33 | def write(addr: UInt, data: UInt) = {
34 | when (addr =/= 0.U) {
35 | regs.write(toIndex(addr), data)
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/test/BottleRocketCoreTB.v:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Unit-level testbench for the BottleRocket core with RISC-V isa tests
16 |
17 | `include "BottleRocketCore.v"
18 | `include "MockAXI4LiteSRAM.v"
19 |
20 | `define MAXCYCLES 100000
21 | `define TOHOSTADDR 'h00006000
22 | `define SUCCESSCODE 1
23 |
24 | module BottleRocketCoreTB(
25 | );
26 |
27 | reg clk;
28 | reg reset;
29 |
30 | wire imem_awvalid;
31 | wire imem_awready;
32 | wire [31:0] imem_awaddr;
33 | wire [2:0] imem_awprot;
34 | wire [3:0] imem_awcache;
35 | wire imem_wvalid;
36 | wire imem_wready;
37 | wire [31:0] imem_wdata;
38 | wire [3:0] imem_wstrb;
39 | wire imem_bvalid;
40 | wire imem_bready;
41 | wire [1:0] imem_bresp;
42 | wire imem_arvalid;
43 | wire imem_arready;
44 | wire [31:0] imem_araddr;
45 | wire [2:0] imem_arprot;
46 | wire [3:0] imem_arcache;
47 | wire imem_rvalid;
48 | wire imem_rready;
49 | wire [1:0] imem_rresp;
50 | wire [31:0] imem_rdata;
51 |
52 |
53 | wire dmem_awvalid;
54 | wire dmem_awready;
55 | wire [31:0] dmem_awaddr;
56 | wire [2:0] dmem_awprot;
57 | wire [3:0] dmem_awcache;
58 | wire dmem_wvalid;
59 | wire dmem_wready;
60 | wire [31:0] dmem_wdata;
61 | wire [3:0] dmem_wstrb;
62 | wire dmem_bvalid;
63 | wire dmem_bready;
64 | wire [1:0] dmem_bresp;
65 | wire dmem_arvalid;
66 | wire dmem_arready;
67 | wire [31:0] dmem_araddr;
68 | wire [2:0] dmem_arprot;
69 | wire [3:0] dmem_arcache;
70 | wire dmem_rvalid;
71 | wire dmem_rready;
72 | wire [1:0] dmem_rresp;
73 | wire [31:0] dmem_rdata;
74 |
75 | MockAXI4LiteSRAM imem(
76 | .aclk(clk),
77 | .aresetn(~reset),
78 | .awvalid(imem_awvalid),
79 | .awready(imem_awready),
80 | .awaddr(imem_awaddr),
81 | .awprot(imem_awprot),
82 | .awcache(imem_awcache),
83 | .wvalid(imem_wvalid),
84 | .wready(imem_wready),
85 | .wdata(imem_wdata),
86 | .wstrb(imem_wstrb),
87 | .bvalid(imem_bvalid),
88 | .bready(imem_bready),
89 | .bresp(imem_bresp),
90 | .arvalid(imem_arvalid),
91 | .arready(imem_arready),
92 | .araddr(imem_araddr),
93 | .arprot(imem_arprot),
94 | .arcache(imem_arcache),
95 | .rvalid(imem_rvalid),
96 | .rready(imem_rready),
97 | .rresp(imem_rresp),
98 | .rdata(imem_rdata)
99 | );
100 |
101 | MockAXI4LiteSRAM dmem(
102 | .aclk(clk),
103 | .aresetn(~reset),
104 | .awvalid(dmem_awvalid),
105 | .awready(dmem_awready),
106 | .awaddr(dmem_awaddr),
107 | .awprot(dmem_awprot),
108 | .awcache(dmem_awcache),
109 | .wvalid(dmem_wvalid),
110 | .wready(dmem_wready),
111 | .wdata(dmem_wdata),
112 | .wstrb(dmem_wstrb),
113 | .bvalid(dmem_bvalid),
114 | .bready(dmem_bready),
115 | .bresp(dmem_bresp),
116 | .arvalid(dmem_arvalid),
117 | .arready(dmem_arready),
118 | .araddr(dmem_araddr),
119 | .arprot(dmem_arprot),
120 | .arcache(dmem_arcache),
121 | .rvalid(dmem_rvalid),
122 | .rready(dmem_rready),
123 | .rresp(dmem_rresp),
124 | .rdata(dmem_rdata)
125 | );
126 |
127 | BottleRocketCore core(
128 | .clock(clk),
129 | .reset(reset),
130 | .io_constclk(clk),
131 | .io_nmi(1'b0),
132 | .io_eip(1'b0),
133 | .io_dmi_req_ready(),
134 | .io_dmi_req_valid(1'b0),
135 | .io_dmi_req_bits_addr(7'b0),
136 | .io_dmi_req_bits_data(32'b0),
137 | .io_dmi_req_bits_op(2'b0),
138 | .io_dmi_resp_ready(1'b0),
139 | .io_dmi_resp_valid(),
140 | .io_dmi_resp_bits_data(),
141 | .io_dmi_resp_bits_resp(),
142 | .io_wfisleep(),
143 | .io_traceInst(),
144 | .io_traceRetire(),
145 | .io_traceInterrupt(),
146 | .io_traceEret(),
147 | .io_iBus_aw_valid(imem_awvalid),
148 | .io_iBus_aw_ready(imem_awready),
149 | .io_iBus_aw_bits_addr(imem_awaddr),
150 | .io_iBus_aw_bits_prot(imem_awprot),
151 | .io_iBus_aw_bits_cache(imem_awcache),
152 | .io_iBus_w_valid(imem_wvalid),
153 | .io_iBus_w_ready(imem_wready),
154 | .io_iBus_w_bits_data(imem_wdata),
155 | .io_iBus_w_bits_strb(imem_wstrb),
156 | .io_iBus_b_valid(imem_bvalid),
157 | .io_iBus_b_ready(imem_bready),
158 | .io_iBus_b_bits_resp(imem_bresp),
159 | .io_iBus_ar_valid(imem_arvalid),
160 | .io_iBus_ar_ready(imem_arready),
161 | .io_iBus_ar_bits_addr(imem_araddr),
162 | .io_iBus_ar_bits_prot(imem_arprot),
163 | .io_iBus_ar_bits_cache(imem_arcache),
164 | .io_iBus_r_valid(imem_rvalid),
165 | .io_iBus_r_ready(imem_rready),
166 | .io_iBus_r_bits_resp(imem_rresp),
167 | .io_iBus_r_bits_data(imem_rdata),
168 | .io_dBus_aw_valid(dmem_awvalid),
169 | .io_dBus_aw_ready(dmem_awready),
170 | .io_dBus_aw_bits_addr(dmem_awaddr),
171 | .io_dBus_aw_bits_prot(dmem_awprot),
172 | .io_dBus_aw_bits_cache(dmem_awcache),
173 | .io_dBus_w_valid(dmem_wvalid),
174 | .io_dBus_w_ready(dmem_wready),
175 | .io_dBus_w_bits_data(dmem_wdata),
176 | .io_dBus_w_bits_strb(dmem_wstrb),
177 | .io_dBus_b_valid(dmem_bvalid),
178 | .io_dBus_b_ready(dmem_bready),
179 | .io_dBus_b_bits_resp(dmem_bresp),
180 | .io_dBus_ar_valid(dmem_arvalid),
181 | .io_dBus_ar_ready(dmem_arready),
182 | .io_dBus_ar_bits_addr(dmem_araddr),
183 | .io_dBus_ar_bits_prot(dmem_arprot),
184 | .io_dBus_ar_bits_cache(dmem_arcache),
185 | .io_dBus_r_valid(dmem_rvalid),
186 | .io_dBus_r_ready(dmem_rready),
187 | .io_dBus_r_bits_resp(dmem_rresp),
188 | .io_dBus_r_bits_data(dmem_rdata)
189 | );
190 |
191 |
192 | integer ncycles;
193 |
194 | reg [1023:0] image;
195 |
196 | initial begin
197 | if ($value$plusargs("image=%s", image)) begin
198 | $readmemh({image,".hex"}, imem.mem);
199 | $readmemh({image,".hex"}, dmem.mem);
200 | $shm_open({image,".dump.d"});
201 | end else begin
202 | $fatal;
203 | end
204 | $shm_probe("AMC");
205 | $recordvars(core);
206 | ncycles = 0;
207 | clk = 1'b0;
208 | reset = 1'b1;
209 | repeat(20) #5 clk = ~clk;
210 | reset = 1'b0;
211 | forever #5 clk = ~clk;
212 | end
213 |
214 | always @(posedge clk) begin
215 | ncycles = ncycles + 1;
216 | if (ncycles > `MAXCYCLES) begin
217 | $info("Failure: timeout!\n");
218 | $shm_close;
219 | $fatal;
220 | end
221 | end
222 |
223 | always @(posedge clk) begin
224 | if (dmem_awvalid && dmem_wvalid && dmem_awaddr == `TOHOSTADDR) begin
225 | if (dmem_wdata == `SUCCESSCODE) begin
226 | $info("Success!\n");
227 | $shm_close;
228 | $finish;
229 | end else begin
230 | $info("Failure!\n");
231 | $shm_close;
232 | $fatal;
233 | end
234 | end
235 | end
236 |
237 | endmodule
238 |
--------------------------------------------------------------------------------
/test/Makefile:
--------------------------------------------------------------------------------
1 | # Copyright 2017 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | RISCV_TEST_BASE = ../third_party/rocket-chip/riscv-tools/riscv-tests
16 | GEN_SRC_DIR = ../generated-src
17 |
18 | RISCV_GCC = riscv32-unknown-elf-gcc
19 | RISCV_GCC_OPTS = -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
20 | RISCV_OBJDUMP = riscv32-unknown-elf-objdump
21 |
22 | NCVERILOG_OPTS = +incdir+$(GEN_SRC_DIR) +sv +nctimescale+1ns/1ns +access+r +nclicq
23 |
24 | SIM ?= ncverilog
25 | SIM_OPTS ?= $(NCVERILOG_OPTS)
26 |
27 | # fence_i not supported for Harvard architecture
28 | RV32UI_TESTS = addi \
29 | add \
30 | andi \
31 | and \
32 | auipc \
33 | beq \
34 | bge \
35 | bgeu \
36 | blt \
37 | bltu \
38 | bne \
39 | jalr \
40 | jal \
41 | lb \
42 | lbu \
43 | lh \
44 | lhu \
45 | lui \
46 | lw \
47 | ori \
48 | or \
49 | sb \
50 | sh \
51 | simple \
52 | slli \
53 | sll \
54 | slti \
55 | sltiu \
56 | slt \
57 | sltu \
58 | srai \
59 | sra \
60 | srli \
61 | srl \
62 | sub \
63 | sw \
64 | xori \
65 | xor
66 |
67 | RV32MI_TESTS = breakpoint \
68 | csr \
69 | illegal \
70 | ma_addr \
71 | ma_fetch \
72 | mcsr \
73 | sbreak \
74 | scall \
75 | shamt
76 |
77 | TESTS = $(RV32UI_TESTS) # $(RV32MI_TESTS)
78 |
79 | default: $(addsuffix .log, $(TESTS))
80 |
81 | %.log: %.hex %.elf $(GEN_SRC_DIR)/*.v *.v
82 | $(RISCV_OBJDUMP) -D $*.elf > $*.objdump
83 | $(SIM) $(SIM_OPTS) +image=$* BottleRocketCoreTB.v &> $*.log
84 |
85 | %.hex: %.elf
86 | elf2hex 4 32768 $< > $@
87 |
88 | %.elf: $(RISCV_TEST_BASE)/isa/rv32ui/%.S
89 | $(RISCV_GCC) $(RISCV_GCC_OPTS) -I$(RISCV_TEST_BASE)/env/p -I$(RISCV_TEST_BASE)/isa/macros/scalar -Ttest.ld -o $@ $<
90 |
91 | %.elf: $(RISCV_TEST_BASE)/isa/rv32mi/%.S
92 | $(RISCV_GCC) $(RISCV_GCC_OPTS) -I$(RISCV_TEST_BASE)/env/p -I$(RISCV_TEST_BASE)/isa/macros/scalar -Ttest.ld -o $@ $<
93 |
94 | .SECONDARY: $(addsuffix .elf, $(TESTS)) $(addsuffix .hex, $(TESTS))
95 |
96 | .PHONY: clean
97 |
98 | clean:
99 | rm -rf *.hex *.elf *.log ncverilog* INCA_libs data *.log *.dsn *.trn *.dump.d
100 |
--------------------------------------------------------------------------------
/test/MockAXI4LiteSRAM.v:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Mock AXI4Lite SRAM for unit testing the BottleRocket core
16 |
17 | module MockAXI4LiteSRAM (
18 | input aclk,
19 | input aresetn,
20 | input awvalid,
21 | output logic awready,
22 | input [31:0] awaddr,
23 | input [2:0] awprot,
24 | input [3:0] awcache,
25 | input wvalid,
26 | output wready,
27 | input [31:0] wdata,
28 | input [3:0] wstrb,
29 | output logic bvalid,
30 | input bready,
31 | output [1:0] bresp,
32 | input arvalid,
33 | output logic arready,
34 | input [31:0] araddr,
35 | input [2:0] arprot,
36 | input [3:0] arcache,
37 | output logic rvalid,
38 | input rready,
39 | output [1:0] rresp,
40 | output logic [31:0] rdata
41 | );
42 |
43 | logic [31:0] mem [0:32767];
44 |
45 | logic write_active;
46 | logic [3:0] write_resp_delay;
47 | logic [3:0] write_strb;
48 | logic [31:0] write_data;
49 | logic [31:0] write_addr;
50 |
51 | logic read_active;
52 | logic [3:0] read_resp_delay;
53 | logic [31:0] read_data;
54 | logic [31:0] read_addr;
55 |
56 | // Writes
57 | // TODO (amagyar): handle awvalid / wvalid independently
58 |
59 | always @(posedge aclk) begin
60 | if (awvalid && awready && wvalid && wready) begin
61 | write_resp_delay <= $random;
62 | end else if (write_active && write_resp_delay != 0) begin
63 | write_resp_delay <= write_resp_delay - 1;
64 | end
65 | end
66 |
67 | always @(posedge aclk) begin
68 | if (!aresetn) begin
69 | write_active <= 1'b0;
70 | end else if (awvalid && awready && wvalid && wready) begin
71 | write_active <= 1'b1;
72 | end else if (bvalid && bready) begin
73 | write_active <= 1'b0;
74 | end
75 | end // always @ (posedge aclk)
76 |
77 | always @(posedge aclk) begin
78 | if (awvalid && awready && wvalid && wready) begin
79 | if (wstrb[0])
80 | mem[awaddr[31:2]][7:0] <= wdata[7:0];
81 | if (wstrb[1])
82 | mem[awaddr[31:2]][15:8] <= wdata[15:8];
83 | if (wstrb[2])
84 | mem[awaddr[31:2]][23:16] <= wdata[23:16];
85 | if (wstrb[3])
86 | mem[awaddr[31:2]][31:24] <= wdata[31:24];
87 | end
88 | end
89 |
90 | assign awready = !write_active || (bready && bvalid);
91 | assign wready = !write_active || (bready && bvalid);
92 | assign bvalid = write_active && write_resp_delay == 0;
93 | assign bresp = 2'b0;
94 |
95 | // Reads
96 |
97 | always @(posedge aclk) begin
98 | if (arvalid && arready) begin
99 | read_resp_delay <= $random;
100 | end else if (read_active && read_resp_delay != 0) begin
101 | read_resp_delay <= read_resp_delay - 1;
102 | end
103 | end
104 |
105 | always @(posedge aclk) begin
106 | if (!aresetn) begin
107 | read_active <= 1'b0;
108 | end else if (arvalid && arready) begin
109 | read_active <= 1'b1;
110 | read_addr <= araddr;
111 | end else if (rvalid && rready) begin
112 | read_active <= 1'b0;
113 | end
114 | end // always @ (posedge aclk)
115 |
116 | always @(*) begin
117 | rdata = mem[read_addr[31:2]];
118 | end
119 |
120 | assign arready = !read_active || (rready && rvalid);
121 | assign rvalid = read_active && read_resp_delay == 0;
122 | assign rresp = 2'b0;
123 |
124 | endmodule // MockAXI4LiteSRAM
125 |
--------------------------------------------------------------------------------
/test/test.ld:
--------------------------------------------------------------------------------
1 | /* Copyright 2017 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | */
15 |
16 | OUTPUT_ARCH( "riscv" )
17 | ENTRY(_start)
18 |
19 | SECTIONS
20 | {
21 | . = 0x0004100;
22 | .text.init : AT(ADDR(.text.init)) { *(.text.init) }
23 | .tohost ALIGN(0x2000) : AT(ADDR(.tohost)) { *(.tohost) }
24 | .text ALIGN(0x1000) : AT(ADDR(.text)) { *(.text) }
25 | .data ALIGN(0x1000) : AT(ADDR(.data)) { *(.data) }
26 | .bss : AT(ADDR(.bss)) { *(.bss) }
27 | _end = .;
28 | }
29 |
30 |
--------------------------------------------------------------------------------