Skip to content

Commit a93308b

Browse files
committed
update
Implemented a bunch of instructions Improved testbenches A bit of documentation written
1 parent f2954d4 commit a93308b

File tree

10 files changed

+1296
-369
lines changed

10 files changed

+1296
-369
lines changed

README.md

Lines changed: 88 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,112 +1,119 @@
1-
Chisel Project Template
2-
=======================
1+
# MIT OpenCompute RISC-V Project
32

4-
You've done the [Chisel Bootcamp](https://github.com/freechipsproject/chisel-bootcamp), and now you
5-
are ready to start your own Chisel project. The following procedure should get you started
6-
with a clean running [Chisel3](https://www.chisel-lang.org/) project.
3+
This is the MIT OpenCompute Laboratory’s RISC-V Project.
4+
We are designing a 32-bit CPU that implements the RV32I RISC-V ISA.
75

8-
## Make your own Chisel3 project
6+
---
97

10-
### Dependencies
8+
## Project Structure
119

12-
#### JDK 11 or newer
10+
CPU HDL files are stored in: ```main\scala\RISCV```
1311

14-
We recommend using Java 11 or later LTS releases. While Chisel itself works with Java 8, our preferred build tool Mill requires Java 11. You can install the JDK as your operating system recommends, or use the prebuilt binaries from [Adoptium](https://adoptium.net/) (formerly AdoptOpenJDK).
1512

16-
#### SBT or mill
13+
### ALU.scala
1714

18-
SBT is the most common build tool in the Scala community. You can download it [here](https://www.scala-sbt.org/download.html).
19-
Mill is another Scala/Java build tool preferred by Chisel's developers.
20-
This repository includes a bootstrap script `./mill` so that no installation is necessary.
21-
You can read more about Mill on its website: https://mill-build.org.
15+
Defines the Arithmetic Logic Unit (ALU) hardware.
2216

23-
#### Verilator
17+
The ALU takes two operands, `a` and `b`, and sends the result of the operation to `output`.
18+
It also accepts two control inputs:
19+
- A 4-bit operation code.
20+
- A sign-flag boolean, used only for comparisons.
2421

25-
The test with `svsim` needs Verilator installed.
26-
See Verilator installation instructions [here](https://verilator.org/guide/latest/install.html).
22+
#### Operation Codes
2723

28-
### How to get started
24+
| Code | Operation |
25+
|-------|--------------------------|
26+
| 0000 | Addition |
27+
| 0001 | Multiplication |
28+
| 0010 | Comparison (gt, eq, lt) |
29+
| 0011 | Bitwise AND |
30+
| 0100 | Bitwise OR |
31+
| 0101 | Bitwise XOR |
32+
| 0110 | Bitwise NOT (outputs NOT a) |
33+
| 0111 | Logical shift left |
34+
| 1000 | Logical shift right |
35+
| 1001 | Arithmetic shift right |
2936

30-
#### Create a repository from the template
37+
The sign flag determines whether operands are treated as signed or unsigned values for comparison.
3138

32-
This repository is a Github template. You can create your own repository from it by clicking the green `Use this template` in the top right.
33-
Please leave `Include all branches` **unchecked**; checking it will pollute the history of your new repository.
34-
For more information, see ["Creating a repository from a template"](https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/creating-a-repository-from-a-template).
39+
---
3540

36-
#### Wait for the template cleanup workflow to complete
41+
### Decoder.scala
3742

38-
After using the template to create your own blank project, please wait a minute or two for the `Template cleanup` workflow to run which will removes some template-specific stuff from the repository (like the LICENSE).
39-
Refresh the repository page in your browser until you see a 2nd commit by `actions-user` titled `Template cleanup`.
43+
Implements the RISC-V instruction decoder that extracts key fields from a 32-bit instruction and formats them for downstream units such as the ALU, register file, or control logic.
4044

45+
The decoder:
46+
- Identifies the instruction format (R, I, S, B, U, or J) based on the opcode (bits 6–0).
47+
- Outputs:
48+
- `rs1`, `rs2`, and `rd` register indices
49+
- The operation code (`operation`)
50+
- The immediate value (`immediate`)
4151

42-
#### Clone your repository
52+
For each format, the corresponding immediate field is assembled and sign-extended (or zero-filled) to 32 bits by left-shifting the extracted bits and padding with zeros as needed.
53+
This ensures that all immediates output by the decoder are consistently 32 bits wide, ready for arithmetic or address calculations without additional shifting logic later in the datapath.
4354

44-
Once you have created a repository from this template and the `Template cleanup` workflow has completed, you can click the green button to get a link for cloning your repository.
45-
Note that it is easiest to push to a repository if you set up SSH with Github, please see the [related documentation](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/connecting-to-github-with-ssh). SSH is required for pushing to a Github repository when using two-factor authentication.
55+
---
4656

47-
```sh
48-
git clone git@github.com:MIT-OpenCompute/RISC-V.git
49-
cd RISC-V
50-
```
57+
### Registers.scala
5158

52-
#### Set project organization and name in build.sbt
59+
Defines the register file hardware.
5360

54-
The cleanup workflow will have attempted to provide sensible defaults for `ThisBuild / organization` and `name` in the `build.sbt`.
55-
Feel free to use your text editor of choice to change them as you see fit.
61+
The CPU register file supports:
62+
- Dual independent combinational reads.
63+
- A single independent synchronous write.
5664

57-
#### Clean up the README.md file
65+
This allows two registers to be read in one clock cycle while a third register is written simultaneously.
5866

59-
Again, use you editor of choice to make the README specific to your project.
67+
The module also includes a third, debugging-only read port called the **C port**.
68+
This port is used exclusively for reading register values from testbenches.
69+
It is not part of the actual hardware and should not be used in the CPU datapath.
6070

61-
#### Add a LICENSE file
71+
---
6272

63-
It is important to have a LICENSE for open source (or closed source) code.
64-
This template repository has the Unlicense in order to allow users to add any license they want to derivative code.
65-
The Unlicense is stripped when creating a repository from this template so that users do not accidentally unlicense their own work.
73+
## Running Testbenches
6674

67-
For more information about a license, check out the [Github Docs](https://docs.github.com/en/free-pro-team@latest/github/building-a-strong-community/adding-a-license-to-a-repository).
75+
This project uses `sbt`.
6876

69-
#### Commit your changes
70-
```sh
71-
git commit -m 'Starting RISC-V'
72-
git push origin main
77+
To run a specific testbench, such as `ALUSpec.scala`, execute:
78+
```bash
79+
sbt "testOnly RISCV.ALUSpec"
7380
```
7481

75-
### Did it work?
76-
77-
You should now have a working Chisel3 project.
78-
79-
You can run the included test with:
80-
```sh
81-
sbt test
82-
```
82+
## Writing a Testbench
8383

84-
Alternatively, if you use Mill:
85-
```sh
86-
./mill RISC-V.test
87-
```
84+
Use the following template as a guide for creating new testbenches:
8885

89-
You should see a whole bunch of output that ends with something like the following lines
90-
```
91-
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
92-
[info] All tests passed.
93-
[success] Total time: 5 s, completed Dec 16, 2020 12:18:44 PM
9486
```
95-
If you see the above then...
96-
97-
### It worked!
98-
99-
You are ready to go. We have a few recommended practices and things to do.
100-
101-
* Use packages and following conventions for [structure](https://www.scala-sbt.org/1.x/docs/Directories.html) and [naming](http://docs.scala-lang.org/style/naming-conventions.html)
102-
* Package names should be clearly reflected in the testing hierarchy
103-
* Build tests for all your work
104-
* Read more about testing in SBT in the [SBT docs](https://www.scala-sbt.org/1.x/docs/Testing.html)
105-
* This template includes a [test dependency](https://www.scala-sbt.org/1.x/docs/Library-Dependencies.html#Per-configuration+dependencies) on [ScalaTest](https://www.scalatest.org/). This, coupled with `svsim` (included with Chisel) and `verilator`, are a starting point for testing Chisel generators.
106-
* You can remove this dependency in the build.sbt file if you want to
107-
* Change the name of your project in the build.sbt file
108-
* Change your README.md
109-
110-
## Problems? Questions?
111-
112-
Check out the [Chisel Users Community](https://www.chisel-lang.org/community.html) page for links to get in contact!
87+
package RISCV
88+
89+
import chisel3._
90+
import chisel3.simulator.scalatest.ChiselSim
91+
import org.scalatest.freespec.AnyFreeSpec
92+
import org.scalatest.matchers.must.Matchers
93+
94+
class MainTemplateSpec extends AnyFreeSpec with Matchers with ChiselSim {
95+
96+
"Main should execute an instruction correctly (template)" in {
97+
simulate(new Main()) { dut =>
98+
// 1. Initialize registers (example: write value to x1)
99+
dut.io.write_enable.poke(true.B)
100+
dut.io.write_addr.poke(1.U)
101+
dut.io.in.poke(42.U)
102+
dut.clock.step(1)
103+
dut.io.write_enable.poke(false.B)
104+
105+
// 2. Load an instruction (replace with your own encoding)
106+
val instr = "b000000000000_00000_000_00000_0000000".U(32.W)
107+
dut.io.instruction.poke(instr)
108+
109+
// 3. Step one clock to execute
110+
dut.clock.step(1)
111+
112+
// 4. Read back a register value to verify the result
113+
// Always use the C port of the register file for reading.
114+
dut.io.read_addr_C.poke(1.U) // Which register to read
115+
dut.io.out_C.expect(42.U) // Expected result (example)
116+
}
117+
}
118+
}
119+
```

src/main/scala/RISCV/ALU.scala

Lines changed: 72 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,85 @@ import _root_.circt.stage.ChiselStage
66

77
/**
88
* @param width Bit width (default: 32 bits)
9+
*
10+
* The Arithmetic Logic Unit (ALU) for RISC-V
11+
* Supports: Addition, Multiplication, Comparison, Bitwise operations
12+
*
13+
* I/O:
14+
* operation: 4-bit operation code
15+
* signed: boolean to indicate if operands are signed (Only used for comparisons)
16+
* a: first operand
17+
* b: second operand
18+
* output: result of the operation
19+
*
20+
* Operation Codes:
21+
* 0000: Addition
22+
* 0001: Multiplication
23+
* 0010: Comparison (outputs 3 bits: gt, eq, lt)
24+
* 0011: Bitwise AND
25+
* 0100: Bitwise OR
26+
* 0101: Bitwise XOR
27+
* 0110: Bitwise NOT (outputs NOT a)
28+
* 0111: Logical shift left
29+
* 1000: Logical shift right
30+
* 1001: Arithmetic shift right
31+
*
932
*/
1033
class ALU(val width: Int = 32) extends Module {
1134
val io = IO(new Bundle {
12-
val add = Input(Bool());
13-
val compare = Input(Bool());
14-
15-
val a = Input(UInt(width.W));
16-
val b = Input(UInt(width.W));
17-
18-
val output = Output(UInt(width.W));
35+
val operation = Input(UInt(4.W)); // 4-bit operation code
36+
val signed = Input(Bool()); // Treat operands as signed if true
37+
val a = Input(UInt(width.W)); // First operand
38+
val b = Input(UInt(width.W)); // Second operand
39+
val output = Output(UInt(width.W)); // Result of the operation
1940
})
2041

21-
when(io.compare) {
22-
val gt = io.a > io.b;
23-
val eq = io.a === io.b;
24-
val lt = io.a < io.b;
42+
io.output := 0.U;
43+
44+
switch(io.operation) {
45+
is("b0000".U) {
46+
io.output := io.a + io.b; // Addition
47+
}
48+
is("b0001".U) {
49+
io.output := io.a * io.b; // Multiplication
50+
}
51+
is("b0010".U) {
52+
when(io.signed) {
53+
val a_s = io.a.asSInt
54+
val b_s = io.b.asSInt
55+
val gt_s = a_s > b_s
56+
val eq_s = a_s === b_s
57+
val lt_s = a_s < b_s
58+
io.output := Cat(0.U((width - 3).W), gt_s, eq_s, lt_s);
59+
} .otherwise {
60+
val gt = io.a > io.b; // Comparison
61+
val eq = io.a === io.b;
62+
val lt = io.a < io.b;
2563

26-
io.output := Cat(0.U((width - 3).W), gt, eq, lt);
27-
}.otherwise {
28-
when(io.add) {
29-
io.output := io.a + io.b;
30-
}.otherwise {
31-
io.output := io.a * io.b;
64+
io.output := Cat(0.U((width - 3).W), gt, eq, lt);
3265
}
66+
}
67+
is("b0011".U) {
68+
io.output := io.a & io.b; // Bitwise AND
69+
}
70+
is("b0100".U) {
71+
io.output := io.a | io.b; // Bitwise OR
72+
}
73+
is("b0101".U) {
74+
io.output := io.a ^ io.b; // Bitwise XOR
75+
}
76+
is("b0110".U) {
77+
io.output := ~io.a; // Bitwise NOT
78+
}
79+
is("b0111".U) {
80+
io.output := io.a << io.b(4,0); // Logical shift left
81+
}
82+
is("b1000".U) {
83+
io.output := io.a >> io.b(4,0); // Logical shift right
84+
}
85+
is("b1001".U) {
86+
io.output := (io.a.asSInt >> io.b(4,0)).asUInt // Arithmetic shift right
87+
}
3388
}
3489
}
3590

0 commit comments

Comments
 (0)