Compare commits

..

3 Commits

@ -28,29 +28,16 @@
├── .gitignore # 用于配置Git忽略文件
├── .vscode # 用于配置VSCode编辑器
├── README.md # 项目说明文档
├── chisel # Chisel代码
│ ├── .bloop # 用于配置Bloop编译器
├── verilog # verilog代码
│ ├── .gitignore # 用于配置Git忽略文件
│ ├── .metals # 用于配置Metals编译器
│ ├── .scalafmt.conf # 用于配置Scalafmt代码格式化工具
│ ├── .vscode # 用于配置VSCode编辑器
│ ├── Makefile # 用于配置Make编译工具
│ ├── README.md # 项目说明文档
│ ├── build # 用于存储Chisel生成的Verilog文件
│ ├── build.sc # 用于配置Mill编译工具
│ ├── out # 用于存储mill编译后的文件
│ ├── playground
│ │ ├── resources # 用于存储CPU设计相关的Verilog文件
│ │ ├── src # 用于存储CPU设计相关的Chisel文件
│ │ └── test # 用于存储CPU设计相关的Chisel测试文件
│ └── utils # 用于存储firtool相关的文件
│ ├── playground # 用于存储CPU设计相关的Verilog文件
├── difftest # 差分测试框架
```
## 🛠️ 环境配置
- 以下配置流程在 Ubuntu22.04 以及 WSL2 的 Ubuntu22.04 版本下得到验证,可顺利执行
- 对于 Mac 用户,可使用 brew 工具直接安装对应的工具(由于 brew 安装的 Mill 的版本较新,需将 chisel/build.sc 的内容替换为 [chisel-playground/build.mill](https://github.com/OSCPU/chisel-playground/blob/master/build.mill) 中的内容以解决环境构建问题)
- 对于 Mac 用户,可使用 brew 工具直接安装对应的工具
- 推荐使用 Ubuntu22.04 版本进行实验,对于其他环境出现的问题请先自己尝试解决
### 🍕 安装 Verilator
@ -87,21 +74,6 @@ sudo apt-get install gtkwave
gtkwave <波形文件的路径>
```
### 🍟 安装 Java
```bash
sudo apt-get install openjdk-11-jdk
java --version # 若安装成功将输出对应版本号
```
### 🌭 安装 Mill
```bash
curl -L https://github.com/com-lihaoyi/mill/releases/download/0.11.6/0.11.6 > mill && chmod +x mill
mv mill /usr/bin/mill
mill --version # 若安装成功将输出对应版本号
```
### 🍖 安装 VS Code
- 安装 VS Code
@ -125,36 +97,14 @@ source ~/.bashrc
echo $RVDIFF_HOME # 查看是否成功输出 difftest 文件夹的路径,这个很重要!
```
### 🥙 环境完整性测试
```bash
cd difftest
git checkout env_test # 切换到 env_test 分支
make envtest # 测试环境完整性
```
观察 chisel/build 目录下是否成功生成 GCD.sv 文件,若成功则说明 Chisel 环境配置成功
观察命令行是否存在以下输出:
```bash
Error!
reference: PC = 0x0000000080000010, wb_rf_wnum = 0x02, wb_rf_wdata = 0x0000000000000001
mycpu : PC = 0x0000000080000010, wb_rf_wnum = 0x02, wb_rf_wdata = 0x0000000000000000
```
若存在类似输出则说明差分测试环境配置成功
## 🛸 开始实验
```bash
git checkout main # 切换到 main 分支,实验代码均在 main 分支下
git checkout verilog # 切换到 verilog 分支,实验代码均在 verilog 分支下
git pull # 拉取最新代码
```
建议使用 Vs Code 将 Chisel 目录作为工作目录,可以通过 `code <文件路径>` 命令使用 Vs Code 打开对应文件
所有的 make 指令均在 difftest 目录下执行,如 `make verilog``make lab1``make trace_lab1` 等
所有的 make 指令均在 difftest 目录下执行,如 `make clean``make lab1``make trace_lab1` 等
部分实验存在多个测例,此时 trace.fst 文件需手动生成,在 difftest 目录下使用以下命令手动生成 CPU 波形文件
@ -167,17 +117,16 @@ make trace TESTBIN_DIR=./test/bin/am-tests/01-add-longlong.bin
## 📢 注意事项
- 编程位置位于 chisel
- 编程位置位于 verilog
- 测试位置位于 difftest 中
- 进入 difftest 目录后
- 使用 `make verilog` 生成 verilog 代码(首次实验需要按实验要求补充代码,否则会报错)
- 使用 `make lab1` 进行 实验 1 的测试
- 使用 `make lab1` 进行 实验 1 的测试(首次实验需要按实验要求补充代码,否则会报错)
- 使用 `make trace_lab1` 进行 实验 1 的 CPU 测试记录生成
- 实验 2 为 lab2以此类推
- difftest 目录下的 trace.txt 文件为测试结果,用于提交头歌平台,作为评分依据
- 使用 `make clean` 清理测试相关编译产物
- 在实验时务必确认 git 下有产生实验记录,这是重要的采分点之一,可通过 `git log tracer-rvlab` 查看(如果没有产生实验记录,请检查 RVDIFF_HOME 是否设置正确)
## 📦 资源
- 🧰[RISC-V Convertor](https://luplab.gitlab.io/rvcodecjs/) - RISC-V 汇编转换器
- 📑[Chisel Project Template](https://github.com/OSCPU/chisel-playground) - Chisel 项目模板

@ -1,36 +0,0 @@
version = 2.6.4
maxColumn = 120
align = most
continuationIndent.defnSite = 2
assumeStandardLibraryStripMargin = true
docstrings = ScalaDoc
lineEndings = preserve
includeCurlyBraceInSelectChains = false
danglingParentheses = true
align.tokens.add = [
{
code = ":"
},
{
code = ":="
},
{
code = "="
},
{
code = "->"
}
]
newlines.alwaysBeforeCurlyBraceLambdaParams = false
newlines.alwaysBeforeMultilineDef = false
newlines.implicitParamListModifierForce = [before]
verticalMultiline.atDefnSite = true
optIn.annotationNewlines = true
rewrite.rules = [SortImports, PreferCurlyFors, AvoidInfix]

@ -1,46 +0,0 @@
BUILD_DIR = ./build
DIFF_DIR = ../difftest/core
DIFF_WORK_DIR = ../difftest
export PATH := $(PATH):$(abspath ./utils)
verilog:
$(call git_commit, "generate verilog") # DO NOT REMOVE THIS LINE!!!
$(MAKE) clean
mkdir -p $(BUILD_DIR)
mill -i __.test.runMain Elaborate -td $(BUILD_DIR)
test:
@echo "make test"
$(call git_commit, "test chisel module") # DO NOT REMOVE THIS LINE!!!
$(MAKE) clean
mkdir -p $(BUILD_DIR)
mill -i __.test.runMain TestMain -td $(BUILD_DIR)
count:
find ./playground/ -name "*.scala" | xargs wc -l
help:
mill -i __.test.runMain Elaborate --help
compile:
mill -i __.compile
bsp:
mill -i mill.bsp.BSP/install
reformat:
mill -i __.reformat
checkformat:
mill -i __.checkFormat
clean:
-rm -rf $(BUILD_DIR)
.PHONY: test verilog help compile bsp reformat checkformat clean
sim:
@echo "Write this Makefile by yourself."
-include ../Makefile

@ -1,38 +0,0 @@
# Chisel Project Template
Another version of the [Chisel template](https://github.com/ucb-bar/chisel-template) supporting mill.
mill is another Scala/Java build tool without obscure DSL like SBT. It is much faster than SBT.
Contents at a glance:
- `.gitignore` - helps Git ignore junk like generated files, build products, and temporary files.
- `build.sc` - instructs mill to build the Chisel project
- `Makefile` - rules to call mill
- `playground/src/GCD.scala` - GCD source file
- `playground/src/DecoupledGCD.scala` - another GCD source file
- `playground/src/Elaborate.scala` - wrapper file to call chisel command with the GCD module
- `playground/test/src/GCDSpec.scala` - GCD tester
Feel free to rename or delete files under `playground/` or use them as a reference/template.
## Getting Started
First, install mill by referring to the documentation [here](https://com-lihaoyi.github.io/mill).
To run all tests in this design (recommended for test-driven development):
```bash
make test
```
To generate Verilog:
```bash
make verilog
```
## Change FIRRTL Compiler
You can change the FIRRTL compiler between SFC (Scala-based FIRRTL compiler) and
MFC (MLIR-based FIRRTL compiler) by modifying the `useMFC` variable in `playground/src/Elaborate.scala`.
The latter one requires `firtool`, which is included under `utils/`.

@ -1,45 +0,0 @@
// import Mill dependency
import mill._
import mill.scalalib._
import mill.scalalib.scalafmt.ScalafmtModule
import mill.scalalib.TestModule.ScalaTest
// support BSP
import mill.bsp._
object playground extends ScalaModule with ScalafmtModule { m =>
val useChisel5 = false
val useChisel6 = true
override def scalaVersion = "2.13.10"
override def scalacOptions = Seq(
"-language:reflectiveCalls",
"-deprecation",
"-feature",
"-Xcheckinit"
)
override def ivyDeps = Agg(
if (useChisel5) ivy"org.chipsalliance::chisel:5.0.0"
else if (useChisel6) ivy"org.chipsalliance::chisel:6.1.0"
else
ivy"edu.berkeley.cs::chisel3:3.6.0"
)
override def scalacPluginIvyDeps = Agg(
if (useChisel5) ivy"org.chipsalliance:::chisel-plugin:5.0.0"
else if (useChisel6) ivy"org.chipsalliance:::chisel-plugin:6.1.0"
else
ivy"edu.berkeley.cs:::chisel3-plugin:3.6.0"
)
object test extends ScalaTests with ScalaTest {
override def ivyDeps = m.ivyDeps() ++ Agg(
ivy"com.lihaoyi::utest:0.8.1",
if (useChisel5 || useChisel6) ivy"edu.berkeley.cs::chiseltest:5.0.0"
else
ivy"edu.berkeley.cs::chiseltest:0.6.0"
)
}
def repositoriesTask = T.task {
Seq(
coursier.MavenRepository("https://maven.aliyun.com/repository/central"),
coursier.MavenRepository("https://repo.scala-sbt.org/scalasbt/maven-releases")
) ++ super.repositoriesTask()
}
}

@ -1,54 +0,0 @@
module top(
input clock,
input reset,
// Interrupts
input mei, // to PLIC
input msi, // to CLINT
input mti, // to CLINT
input sei, // to PLIC
// inst sram interface
output inst_sram_en,
output [ 3:0] inst_sram_wen,
output [31:0] inst_sram_addr,
output [31:0] inst_sram_wdata,
input [31:0] inst_sram_rdata,
// data sram interface
output data_sram_en,
output [ 7:0] data_sram_wen,
output [31:0] data_sram_addr,
output [63:0] data_sram_wdata,
input [63:0] data_sram_rdata,
// trace debug interface
output debug_commit,
output [63:0] debug_pc,
output [4:0 ] debug_rf_wnum,
output [63:0] debug_rf_wdata
);
PuaCpu core(
.clock (clock),
.reset (reset),
// interrupts
.io_ext_int_mei (mei),
.io_ext_int_mti (mti),
.io_ext_int_msi (msi),
// inst sram interface
.io_inst_sram_en (inst_sram_en),
.io_inst_sram_wen (inst_sram_wen),
.io_inst_sram_addr (inst_sram_addr),
.io_inst_sram_wdata (inst_sram_wdata),
.io_inst_sram_rdata (inst_sram_rdata),
// data sram interface
.io_data_sram_en (data_sram_en),
.io_data_sram_wen (data_sram_wen),
.io_data_sram_addr (data_sram_addr),
.io_data_sram_wdata (data_sram_wdata),
.io_data_sram_rdata (data_sram_rdata),
// debug
.io_debug_pc (debug_pc),
.io_debug_commit (debug_commit),
.io_debug_rf_wnum (debug_rf_wnum),
.io_debug_rf_wdata (debug_rf_wdata)
);
endmodule

@ -1,35 +0,0 @@
package cpu
import chisel3._
import chisel3.util._
import defines._
import defines.Const._
import pipeline._
class Core extends Module {
val io = IO(new Bundle {
val interrupt = Input(new ExtInterrupt())
val instSram = new InstSram()
val dataSram = new DataSram()
val debug = new DEBUG()
})
val fetchUnit = Module(new FetchUnit()).io
val decodeStage = Module(new DecodeStage()).io
val decodeUnit = Module(new DecodeUnit()).io
val regfile = Module(new ARegFile()).io
val executeStage = Module(new ExecuteStage()).io
val executeUnit = Module(new ExecuteUnit()).io
val memoryStage = Module(new MemoryStage()).io
val memoryUnit = Module(new MemoryUnit()).io
val writeBackStage = Module(new WriteBackStage()).io
val writeBackUnit = Module(new WriteBackUnit()).io
// 取指单元
fetchUnit.instSram <> io.instSram
fetchUnit.decodeStage <> decodeStage.fetchUnit
// TODO: 完成Core模块的逻辑
// 在该模块中需要将各个模块连接起来形成一个完整的CPU核心
}

@ -1,16 +0,0 @@
package cpu
import chisel3.util._
import cpu.defines.Const._
case class CpuConfig(
// 指令集
val isRV32: Boolean = false, // 是否为RV32
val hasMExtension: Boolean = false, // 是否实现M扩展即乘除法指令
val hasZicsrExtension: Boolean = false, // 是否实现Zicsr扩展即CSR指令
val hasZifenceiExtension: Boolean = false, // 是否实现Zifencei扩展即FENCE.I指令
val hasAExtension: Boolean = false, // 是否实现A扩展即原子指令
// 特权模式
val hasSMode: Boolean = false, // 是否有S模式
val hasUMode: Boolean = false // 是否有U模式
)

@ -1,9 +0,0 @@
import cpu._
import circt.stage._
object Elaborate extends App {
implicit val cpuConfig = new CpuConfig()
def top = new PuaCpu()
val generator = Seq(chisel3.stage.ChiselGeneratorAnnotation(() => top))
(new ChiselStage).execute(args, generator :+ CIRCTTargetAnnotation(CIRCTTarget.Verilog))
}

@ -1,20 +0,0 @@
import chisel3._
import chisel3.util._
import cpu._
import cpu.defines._
class PuaCpu extends Module {
val io = IO(new Bundle {
val ext_int = Input(new ExtInterrupt())
val inst_sram = new InstSram()
val data_sram = new DataSram()
val debug = new DEBUG()
})
val core = Module(new Core())
io.ext_int <> core.io.interrupt
io.inst_sram <> core.io.instSram
io.data_sram <> core.io.dataSram
io.debug <> core.io.debug
}

@ -1,59 +0,0 @@
package cpu.defines
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
import cpu.CpuConfig
class ExtInterrupt extends Bundle {
val mei = Bool()
val mti = Bool()
val msi = Bool()
}
class SrcInfo extends Bundle {
val src1_data = UInt(XLEN.W)
val src2_data = UInt(XLEN.W)
}
class RdInfo extends Bundle {
val wdata = UInt(XLEN.W)
}
class Info extends Bundle {
val valid = Bool() // 用于标识当前流水级中的指令是否有效
val src1_raddr = UInt(REG_ADDR_WID.W)
val src2_raddr = UInt(REG_ADDR_WID.W)
val op = FuOpType()
val reg_wen = Bool()
val reg_waddr = UInt(REG_ADDR_WID.W)
}
class SrcReadSignal extends Bundle {
val ren = Bool()
val raddr = UInt(REG_ADDR_WID.W)
}
class InstSram extends Bundle {
val en = Output(Bool())
val addr = Output(UInt(SRAM_ADDR_WID.W))
val wdata = Output(UInt(INST_SRAM_DATA_WID.W))
val wen = Output(UInt(INST_SRAM_WEN_WID.W))
val rdata = Input(UInt(INST_SRAM_DATA_WID.W))
}
class DataSram extends Bundle {
val en = Output(Bool())
val addr = Output(UInt(SRAM_ADDR_WID.W))
val wdata = Output(UInt(DATA_SRAM_DATA_WID.W))
val wen = Output(UInt(DATA_SRAM_WEN_WID.W))
val rdata = Input(UInt(DATA_SRAM_DATA_WID.W))
}
class DEBUG extends Bundle {
val commit = Output(Bool()) // 写回阶段的commit信号仅在每条指令提交时置为true
val pc = Output(UInt(XLEN.W)) // 写回阶段的pc
val rf_wnum = Output(UInt(REG_ADDR_WID.W)) // 写回阶段的寄存器写地址
val rf_wdata = Output(UInt(XLEN.W)) // 写回阶段的寄存器写数据
}

@ -1,42 +0,0 @@
package cpu.defines
import chisel3._
import chisel3.util._
import cpu.CpuConfig
trait CoreParameter {
def cpuConfig = new CpuConfig
val XLEN = if (cpuConfig.isRV32) 32 else 64
val VADDR_WID = if (cpuConfig.isRV32) 32 else 39
val PADDR_WID = 32
}
trait Constants extends CoreParameter {
// 全局
val PC_INIT = "h80000000".U(XLEN.W)
val INT_WID = 12
val EXC_WID = 16
// inst rom
val INST_WID = 32
// GPR RegFile
val AREG_NUM = 32
val REG_ADDR_WID = 5
}
trait SRAMConst extends Constants {
val SRAM_ADDR_WID = PADDR_WID // 32
val DATA_SRAM_DATA_WID = XLEN
val DATA_SRAM_WEN_WID = XLEN / 8
val INST_SRAM_DATA_WID = INST_WID
val INST_SRAM_WEN_WID = INST_WID / 8
}
object Const extends Constants with SRAMConst
object Instructions extends HasInstrType with CoreParameter {
def NOP = 0x00000013.U
val DecodeDefault = List(InstrN, FuType.alu, ALUOpType.add)
def DecodeTable = RVIInstr.table
}

@ -1,29 +0,0 @@
package cpu.defines
import chisel3._
import chisel3.util._
object SignedExtend {
def apply(a: UInt, len: Int) = {
val aLen = a.getWidth
val signBit = a(aLen - 1)
if (aLen >= len) a(len - 1, 0) else Cat(Fill(len - aLen, signBit), a)
}
}
object ZeroExtend {
def apply(a: UInt, len: Int) = {
val aLen = a.getWidth
if (aLen >= len) a(len - 1, 0) else Cat(0.U((len - aLen).W), a)
}
}
object LookupTree {
def apply[T <: Data](key: UInt, mapping: Iterable[(UInt, T)]): T =
Mux1H(mapping.map(p => (p._1 === key, p._2)))
}
object LookupTreeDefault {
def apply[T <: Data](key: UInt, default: T, mapping: Iterable[(UInt, T)]): T =
MuxLookup(key, default)(mapping.toSeq)
}

@ -1,36 +0,0 @@
package cpu.defines
import chisel3._
import chisel3.util._
// 指令类型
trait HasInstrType {
def InstrN = "b000".U
def InstrI = "b100".U
def InstrR = "b101".U
def InstrS = "b010".U
def InstrB = "b001".U
def InstrU = "b110".U
def InstrJ = "b111".U
// IRUJ类型的指令都需要写寄存器
def isRegWen(instrType: UInt): Bool = instrType(2)
}
// 功能单元类型 Function Unit Type
object FuType {
def num = 1
def alu = 0.U // arithmetic logic unit
def apply() = UInt(log2Up(num).W)
}
// 功能单元操作类型 Function Unit Operation Type
object FuOpType {
def apply() = UInt(5.W) // 宽度与最大的功能单元操作类型宽度一致
}
// 算术逻辑单元操作类型 Arithmetic Logic Unit Operation Type
object ALUOpType {
def add = "b00000".U
// TODO: 定义更多的ALU操作类型
}

@ -1,61 +0,0 @@
package cpu.defines
import chisel3._
import chisel3.util._
object RV32I_ALUInstr extends HasInstrType with CoreParameter {
def ADDI = BitPat("b????????????_?????_000_?????_0010011")
def SLLI = if (XLEN == 32) BitPat("b0000000?????_?????_001_?????_0010011")
else BitPat("b000000??????_?????_001_?????_0010011")
def SLTI = BitPat("b????????????_?????_010_?????_0010011")
def SLTIU = BitPat("b????????????_?????_011_?????_0010011")
def XORI = BitPat("b????????????_?????_100_?????_0010011")
def SRLI = if (XLEN == 32) BitPat("b0000000?????_?????_101_?????_0010011")
else BitPat("b000000??????_?????_101_?????_0010011")
def ORI = BitPat("b????????????_?????_110_?????_0010011")
def ANDI = BitPat("b????????????_?????_111_?????_0010011")
def SRAI = if (XLEN == 32) BitPat("b0100000?????_?????_101_?????_0010011")
else BitPat("b010000??????_?????_101_?????_0010011")
def ADD = BitPat("b0000000_?????_?????_000_?????_0110011")
def SLL = BitPat("b0000000_?????_?????_001_?????_0110011")
def SLT = BitPat("b0000000_?????_?????_010_?????_0110011")
def SLTU = BitPat("b0000000_?????_?????_011_?????_0110011")
def XOR = BitPat("b0000000_?????_?????_100_?????_0110011")
def SRL = BitPat("b0000000_?????_?????_101_?????_0110011")
def OR = BitPat("b0000000_?????_?????_110_?????_0110011")
def AND = BitPat("b0000000_?????_?????_111_?????_0110011")
def SUB = BitPat("b0100000_?????_?????_000_?????_0110011")
def SRA = BitPat("b0100000_?????_?????_101_?????_0110011")
def AUIPC = BitPat("b????????????????????_?????_0010111")
def LUI = BitPat("b????????????????????_?????_0110111")
// 在Decoder模块中搭配ListLookup函数使用
val table = Array(
// ADD指令将被解析为InstrR类型的指令功能单元类型为alu功能单元操作类型为add
ADD -> List(InstrR, FuType.alu, ALUOpType.add)
// TODO: 完成其他指令的解析
)
}
object RV64IInstr extends HasInstrType {
def ADDIW = BitPat("b???????_?????_?????_000_?????_0011011")
def SLLIW = BitPat("b0000000_?????_?????_001_?????_0011011")
def SRLIW = BitPat("b0000000_?????_?????_101_?????_0011011")
def SRAIW = BitPat("b0100000_?????_?????_101_?????_0011011")
def SLLW = BitPat("b0000000_?????_?????_001_?????_0111011")
def SRLW = BitPat("b0000000_?????_?????_101_?????_0111011")
def SRAW = BitPat("b0100000_?????_?????_101_?????_0111011")
def ADDW = BitPat("b0000000_?????_?????_000_?????_0111011")
def SUBW = BitPat("b0100000_?????_?????_000_?????_0111011")
val table = Array(
// TODO: 完成RV64I指令集的解析
)
}
object RVIInstr extends CoreParameter {
val table = RV32I_ALUInstr.table ++
(if (XLEN == 64) RV64IInstr.table else Array.empty)
}

@ -1,41 +0,0 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
import cpu.CpuConfig
class SrcRead extends Bundle {
val raddr = Output(UInt(REG_ADDR_WID.W))
val rdata = Input(UInt(XLEN.W))
}
class Src12Read extends Bundle {
val src1 = new SrcRead()
val src2 = new SrcRead()
}
class RegWrite extends Bundle {
val wen = Output(Bool())
val waddr = Output(UInt(REG_ADDR_WID.W))
val wdata = Output(UInt(XLEN.W))
}
class ARegFile extends Module {
val io = IO(new Bundle {
val read = Flipped(new Src12Read())
val write = Flipped(new RegWrite())
})
// 定义32个XLEN位寄存器
val regs = RegInit(VecInit(Seq.fill(AREG_NUM)(0.U(XLEN.W))))
// 写寄存器堆
// TODO:完成写寄存器堆逻辑
// 注意0号寄存器恒为0
// 读寄存器堆
// TODO:完成读寄存器堆逻辑
// 注意0号寄存器恒为0
}

@ -1,30 +0,0 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
import cpu.CpuConfig
class IfIdData extends Bundle {
val inst = UInt(XLEN.W)
val valid = Bool()
val pc = UInt(XLEN.W)
}
class FetchUnitDecodeUnit extends Bundle {
val data = Output(new IfIdData())
}
class DecodeStage extends Module {
val io = IO(new Bundle {
val fetchUnit = Flipped(new FetchUnitDecodeUnit())
val decodeUnit = new FetchUnitDecodeUnit()
})
val data = RegInit(0.U.asTypeOf(new IfIdData()))
data := io.fetchUnit.data
io.decodeUnit.data := data
}

@ -1,38 +0,0 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
class DecodeUnit extends Module {
val io = IO(new Bundle {
// 输入
val decodeStage = Flipped(new FetchUnitDecodeUnit())
val regfile = new Src12Read()
// 输出
val executeStage = Output(new DecodeUnitExecuteUnit())
})
// 译码阶段完成指令的译码操作以及源操作数的准备
val decoder = Module(new Decoder()).io
decoder.in.inst := io.decodeStage.data.inst
val pc = io.decodeStage.data.pc
val info = Wire(new Info())
info := decoder.out.info
info.valid := io.decodeStage.data.valid
// TODO:完成寄存器堆的读取
// io.regfile.src1.raddr :=
// io.regfile.src2.raddr :=
// TODO: 完成DecodeUnit模块的逻辑
// io.executeStage.data.pc :=
// io.executeStage.data.info :=
// io.executeStage.data.src_info.src1_data :=
// io.executeStage.data.src_info.src2_data :=
}

@ -1,36 +0,0 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
class Decoder extends Module with HasInstrType {
val io = IO(new Bundle {
// inputs
val in = Input(new Bundle {
val inst = UInt(XLEN.W)
})
// outputs
val out = Output(new Bundle {
val info = new Info()
})
})
val inst = io.in.inst
// 根据输入的指令inst从Instructions.DecodeTable中查找对应的指令类型功能单元类型和功能单元操作类型
// 如果找不到匹配的指令则使用Instructions.DecodeDefault作为默认值
// instrTypefuType和fuOpType分别被赋值为Instructions.DecodeTable中的对应值
val instrType :: fuType :: fuOpType :: Nil =
ListLookup(inst, Instructions.DecodeDefault, Instructions.DecodeTable)
val (rs, rt, rd) = (inst(19, 15), inst(24, 20), inst(11, 7))
// TODO: 完成Decoder模块的逻辑
// io.out.info.valid :=
// io.out.info.src1_raddr :=
// io.out.info.src2_raddr :=
// io.out.info.op :=
// io.out.info.reg_wen :=
// io.out.info.reg_waddr :=
}

@ -1,28 +0,0 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
import cpu.CpuConfig
class IdExeData extends Bundle {
val pc = UInt(XLEN.W)
val info = new Info()
val src_info = new SrcInfo()
}
class DecodeUnitExecuteUnit extends Bundle {
val data = new IdExeData()
}
class ExecuteStage extends Module {
val io = IO(new Bundle {
val decodeUnit = Input(new DecodeUnitExecuteUnit())
val executeUnit = Output(new DecodeUnitExecuteUnit())
})
val data = RegInit(0.U.asTypeOf(new IdExeData()))
// TODO: 完成ExecuteStage模块的逻辑
}

@ -1,31 +0,0 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.CpuConfig
import cpu.defines._
import cpu.defines.Const._
import chisel3.util.experimental.BoringUtils
class ExecuteUnit extends Module {
val io = IO(new Bundle {
val executeStage = Input(new DecodeUnitExecuteUnit())
val memoryStage = Output(new ExecuteUnitMemoryUnit())
val dataSram = new DataSram()
})
// 执行阶段完成指令的执行操作
val fu = Module(new Fu()).io
fu.data.pc := io.executeStage.data.pc
fu.data.info := io.executeStage.data.info
fu.data.src_info := io.executeStage.data.src_info
io.dataSram <> fu.dataSram
// TODO: 完成ExecuteUnit模块的逻辑
// io.memoryStage.data.pc :=
// io.memoryStage.data.info :=
// io.memoryStage.data.src_info :=
// io.memoryStage.data.rd_info :=
}

@ -1,32 +0,0 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
import cpu.CpuConfig
class Fu extends Module {
val io = IO(new Bundle {
val data = new Bundle {
val pc = Input(UInt(XLEN.W))
val info = Input(new Info())
val src_info = Input(new SrcInfo())
val rd_info = Output(new RdInfo())
}
val dataSram = new DataSram()
})
val alu = Module(new Alu()).io
io.dataSram.en := false.B
io.dataSram.addr := DontCare
io.dataSram.wdata := DontCare
io.dataSram.wen := 0.U
alu.info := io.data.info
alu.src_info := io.data.src_info
io.data.rd_info.wdata := alu.result
}

@ -1,15 +0,0 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
class Alu extends Module {
val io = IO(new Bundle {
val info = Input(new Info())
val src_info = Input(new SrcInfo())
val result = Output(UInt(XLEN.W))
})
// TODO: 完成ALU模块的逻辑
}

@ -1,41 +0,0 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines.Const._
import cpu.CpuConfig
import cpu.defines._
class FetchUnit extends Module {
val io = IO(new Bundle {
val decodeStage = new FetchUnitDecodeUnit()
val instSram = new InstSram()
})
val boot :: send :: receive :: Nil = Enum(3)
val state = RegInit(boot)
switch(state) {
is(boot) {
state := send
}
is(send) {
state := receive
}
is(receive) {}
}
// 取指阶段完成指令的取指操作
val pc = RegEnable(io.instSram.addr, (PC_INIT - 4.U), state =/= boot)
io.instSram.addr := pc + 4.U
io.decodeStage.data.valid := state === receive
io.decodeStage.data.pc := pc
io.decodeStage.data.inst := io.instSram.rdata
io.instSram.en := !reset.asBool
io.instSram.wen := 0.U
io.instSram.wdata := 0.U
}

@ -1,29 +0,0 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
import cpu.CpuConfig
class ExeMemData extends Bundle {
val pc = UInt(XLEN.W)
val info = new Info()
val rd_info = new RdInfo()
val src_info = new SrcInfo()
}
class ExecuteUnitMemoryUnit extends Bundle {
val data = new ExeMemData()
}
class MemoryStage extends Module {
val io = IO(new Bundle {
val executeUnit = Input(new ExecuteUnitMemoryUnit())
val memoryUnit = Output(new ExecuteUnitMemoryUnit())
})
val data = RegInit(0.U.asTypeOf(new ExeMemData()))
// TODO: 完成MemoryStage模块的逻辑
}

@ -1,21 +0,0 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import chisel3.util.experimental.BoringUtils
import cpu.defines._
import cpu.defines.Const._
import cpu.CpuConfig
class MemoryUnit extends Module {
val io = IO(new Bundle {
val memoryStage = Input(new ExecuteUnitMemoryUnit())
val writeBackStage = Output(new MemoryUnitWriteBackUnit())
})
// 访存阶段完成指令的访存操作
io.writeBackStage.data.pc := io.memoryStage.data.pc
io.writeBackStage.data.info := io.memoryStage.data.info
io.writeBackStage.data.rd_info.wdata := io.memoryStage.data.rd_info.wdata
}

@ -1,27 +0,0 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
import cpu.CpuConfig
class MemWbData extends Bundle {
val pc = UInt(XLEN.W)
val info = new Info()
val rd_info = new RdInfo()
}
class MemoryUnitWriteBackUnit extends Bundle {
val data = new MemWbData()
}
class WriteBackStage extends Module {
val io = IO(new Bundle {
val memoryUnit = Input(new MemoryUnitWriteBackUnit())
val writeBackUnit = Output(new MemoryUnitWriteBackUnit())
})
val data = RegInit(0.U.asTypeOf(new MemWbData()))
// TODO: 完成WriteBackStage模块的逻辑
}

@ -1,19 +0,0 @@
package cpu.pipeline
import chisel3._
import chisel3.util._
import cpu.defines._
import cpu.defines.Const._
import cpu.CpuConfig
class WriteBackUnit extends Module {
val io = IO(new Bundle {
val writeBackStage = Input(new MemoryUnitWriteBackUnit())
val regfile = Output(new RegWrite())
val debug = new DEBUG()
})
// 写回阶段完成数据的写回操作
// 同时该阶段还负责差分测试的比对工作
// TODO: 完成WriteBackUnit模块的逻辑
}

@ -1,9 +0,0 @@
// import cpu._
// import circt.stage._
// object TestMain extends App {
// implicit val cpuConfig = new CpuConfig()
// def top = new Top()
// val generator = Seq(chisel3.stage.ChiselGeneratorAnnotation(() => top))
// (new ChiselStage).execute(args, generator :+ CIRCTTargetAnnotation(CIRCTTarget.Verilog))
// }

@ -1,2 +0,0 @@
#!/usr/bin/env bash
firtool.elf.strip --lowering-options=disallowLocalVariables,disallowPackedArrays,locationInfoStyle=wrapInAtSquareBracket $@

Binary file not shown.

@ -1,8 +1,6 @@
TOP_NAME := top
SRC_DIR := ./core
SRC_DIR := ../verilog/playground
SRC_FILE := $(shell find $(SRC_DIR) -name '*.svh') $(shell find $(SRC_DIR) -name '*.h') $(shell find $(SRC_DIR) -name '*.v') $(shell find $(SRC_DIR) -name '*.sv')
CHISEL_DIR = ../chisel
BUILD_DIR = $(CHISEL_DIR)/build
TESTBIN_DIR = ./test/bin/am-tests/add.bin
.PHONY: clean
@ -10,20 +8,12 @@ TESTBIN_DIR = ./test/bin/am-tests/add.bin
obj_dir/V$(TOP_NAME): src/* $(SRC_FILE)
verilator --cc -Wno-fatal --exe --trace-fst --trace-structs -LDFLAGS "-lpthread" --build src/sim_mycpu.cpp $(SRC_FILE) -I$(SRC_DIR) --top $(TOP_NAME) -j `nproc`
verilog:
$(MAKE) -C $(CHISEL_DIR) verilog
cp $(CHISEL_DIR)/build/PuaCpu.v $(SRC_DIR)
trace: obj_dir/V$(TOP_NAME)
$(call git_commit, "trace") # DO NOT REMOVE THIS LINE!!!
./obj_dir/V$(TOP_NAME) $(TESTBIN_DIR) -rvtest -trace 10000000 -pc
test:
$(MAKE) -C $(CHISEL_DIR) test
clean:
rm -rf obj_dir
rm -rf core/PuaCpu.v
perf: obj_dir/V$(TOP_NAME)
$(call git_commit, "perf test RTL") # DO NOT REMOVE THIS LINE!!!

@ -1,54 +0,0 @@
module top(
input clock,
input reset,
// Interrupts
input mei, // to PLIC
input msi, // to CLINT
input mti, // to CLINT
input sei, // to PLIC
// inst sram interface
output inst_sram_en,
output [ 3:0] inst_sram_wen,
output [31:0] inst_sram_addr,
output [31:0] inst_sram_wdata,
input [31:0] inst_sram_rdata,
// data sram interface
output data_sram_en,
output [ 7:0] data_sram_wen,
output [31:0] data_sram_addr,
output [63:0] data_sram_wdata,
input [63:0] data_sram_rdata,
// trace debug interface
output debug_commit,
output [63:0] debug_pc,
output [4:0 ] debug_rf_wnum,
output [63:0] debug_rf_wdata
);
PuaCpu core(
.clock (clock),
.reset (reset),
// interrupts
.io_ext_int_mei (mei),
.io_ext_int_mti (mti),
.io_ext_int_msi (msi),
// inst sram interface
.io_inst_sram_en (inst_sram_en),
.io_inst_sram_wen (inst_sram_wen),
.io_inst_sram_addr (inst_sram_addr),
.io_inst_sram_wdata (inst_sram_wdata),
.io_inst_sram_rdata (inst_sram_rdata),
// data sram interface
.io_data_sram_en (data_sram_en),
.io_data_sram_wen (data_sram_wen),
.io_data_sram_addr (data_sram_addr),
.io_data_sram_wdata (data_sram_wdata),
.io_data_sram_rdata (data_sram_rdata),
// debug
.io_debug_pc (debug_pc),
.io_debug_commit (debug_commit),
.io_debug_rf_wnum (debug_rf_wnum),
.io_debug_rf_wdata (debug_rf_wdata)
);
endmodule

@ -0,0 +1,17 @@
`ifndef MYCPU_H
`define MYCPU_H
`define XLEN 64
// IF_ID_WID = valid + pc + inst = 1 + 64 + 64 = 129
`define IF_ID_WID 129
`define FU_OP_TYPE_WID 5
// INFO_WID = src1_addr + src2_addr + reg_wen + reg_waddr + op
// = 5 + 5 + 1 + 5 + `FU_OP_TYPE_WID = 16 + `FU_OP_TYPE_WID
`define INFO_WID (16 +`FU_OP_TYPE_WID)
// ID_EXE_WID = valid + pc + op + reg_wen + reg_waddr + src1_rdata + src2_rdata
// = 1 + 64 + `FU_OP_TYPE_WID + 1 + 5 + 64 + 64 = 199 + `FU_OP_TYPE_WID
`define ID_EXE_WID (199 + `FU_OP_TYPE_WID)
// EXE_MEM_WID = valid + pc + reg_wen + reg_waddr + reg_wdata
// = 1 + 64 + 1 + 5 + 64 = 135
`define EXE_MEM_WID 135
`define MEM_WB_WID 135
`endif

@ -0,0 +1,40 @@
`include "mycpu.h"
module ARegfile(
input clock,
input reset,
// src1
input [4: 0] src1_raddr,
output [`XLEN - 1: 0] src1_rdata,
// src2
input [4: 0] src2_raddr,
output [`XLEN - 1: 0] src2_rdata,
// writeback
input reg_wen,
input [4: 0] reg_waddr,
input [`XLEN - 1: 0] reg_wdata
);
reg [`XLEN - 1: 0] regs[31: 0];
always @(posedge clock)
begin
if (reset)
begin
// TODO:
// :lab1x0 = 0, x1 = 1, x2 = 2, ..., x31 = 31
// 0
end
else
begin
//
// TODO:
// :x00
end
end
//
// TODO:
// :x00
endmodule

@ -0,0 +1,41 @@
`include "mycpu.h"
module DecodeUnit(
// DecodeStage
input [`IF_ID_WID - 1: 0] decodeStage,
// ARegfile
output [4: 0] src1_raddr,
input [`XLEN - 1: 0] src1_rdata,
output [4: 0] src2_raddr,
input [`XLEN - 1: 0] src2_rdata,
// ExecuteStage
output [`ID_EXE_WID - 1: 0] executeStage
);
wire valid;
wire [`XLEN - 1: 0] pc;
wire [`XLEN - 1: 0] inst;
assign {valid, pc, inst} = decodeStage;
// outports wire
wire [`INFO_WID - 1: 0] info;
// TODO:
wire [`FU_OP_TYPE_WID - 1: 0] op;
wire reg_wen;
wire [4: 0] reg_waddr;
assign {src1_raddr, src2_raddr, op, reg_wen, reg_waddr} = info;
assign executeStage = {
valid,
pc,
op,
reg_wen,
reg_waddr,
src1_rdata,
src2_rdata
};
endmodule

@ -0,0 +1,45 @@
`include "mycpu.h"
module Decoder(
input [`XLEN - 1: 0] inst,
output [`INFO_WID - 1: 0] info
);
// TODO:
wire [6: 0] opcode = inst[6: 0];
// wire [2: 0] funct3 =
// wire [6: 0] funct7 =
// wire [4: 0] rs =
// wire [4: 0] rt =
// wire [4: 0] rd =
wire inst_add = (opcode == 7'b0110011) && (funct3 == 3'b000) && (funct7 == 7'b0000000);
// wire inst_sub =
// wire inst_sll =
// wire inst_slt =
// wire inst_sltu =
// wire inst_xor =
// wire inst_srl =
// wire inst_sra =
// wire inst_or =
// wire inst_and =
// wire inst_addw =
// wire inst_subw =
// wire inst_sllw =
// wire inst_srlw =
// wire inst_sraw =
wire [4: 0] src1_raddr = rs;
wire [4: 0] src2_raddr = rt;
// wire [`FU_OP_TYPE_WID - 1: 0] op =
// wire reg_wen =
// wire [4: 0] reg_waddr =
assign info = {
src1_raddr,
src2_raddr,
op,
reg_wen,
reg_waddr
};
endmodule

@ -0,0 +1,26 @@
`include "mycpu.h"
module DecoderStage(
input clock,
input reset,
input [`IF_ID_WID - 1: 0] fetchUnit,
output [`IF_ID_WID - 1: 0] decodeUnit
);
reg [`IF_ID_WID - 1: 0] data;
always @(posedge clock)
begin
if (reset)
begin
data <= 0;
end
else
begin
data <= fetchUnit;
end
end
assign decodeUnit = data;
endmodule

@ -0,0 +1,12 @@
`include "mycpu.h"
module Alu(
input [`FU_OP_TYPE_WID - 1: 0] op,
input [`XLEN - 1: 0] src1_data,
input [`XLEN - 1: 0] src2_data,
output [`XLEN - 1: 0] result
);
// TODO: ALU
endmodule

@ -0,0 +1,12 @@
`include "mycpu.h"
module ExecuteStage(
input clock,
input reset,
input [`ID_EXE_WID - 1: 0] decodeUnit,
output [`ID_EXE_WID - 1: 0] executeUnit
);
// TODO: ExcuteStage
endmodule

@ -0,0 +1,41 @@
`include "mycpu.h"
module ExecuteUnit(
// ExecuteStage
input [`ID_EXE_WID - 1: 0] executeStage,
// MemoryStage
output [`EXE_MEM_WID - 1: 0] memoryStage,
// memory sram
output data_sram_en,
output [7: 0] data_sram_wen,
output [31: 0] data_sram_addr,
output [63: 0] data_sram_wdata
);
wire valid;
wire [`XLEN - 1: 0] pc;
wire [`FU_OP_TYPE_WID - 1: 0] op;
wire reg_wen;
wire [4: 0] reg_waddr;
wire [`XLEN - 1: 0] src1_data;
wire [`XLEN - 1: 0] src2_data;
assign {valid, pc, op, reg_wen, reg_waddr, src1_data, src2_data} = executeStage;
wire [`XLEN - 1: 0] reg_wdata;
Alu u_Alu(
.op ( op ),
.src1_data ( src1_data ),
.src2_data ( src2_data ),
.result ( reg_wdata )
);
assign data_sram_en = 1'b0;
assign data_sram_wen = 8'b0;
assign data_sram_addr = 32'b0;
assign data_sram_wdata = 64'b0;
// TODO:MemoryStage
// assign memoryStage =
endmodule

@ -0,0 +1,66 @@
`include "mycpu.h"
module FetchUnit(
input clock,
input reset,
output [`IF_ID_WID - 1: 0] decodeStage,
// inst sram interface
output inst_sram_en,
output [ 3: 0] inst_sram_wen,
output [31: 0] inst_sram_addr,
output [31: 0] inst_sram_wdata,
input [31: 0] inst_sram_rdata
);
reg [1: 0] state;
parameter boot = 0;
parameter send = 1;
parameter receive = 2;
always @(posedge clock)
begin
if (reset)
begin
state <= boot;
end
else
begin
case (state)
boot:
state <= send;
send:
state <= receive;
receive:
;
endcase
end
end
reg [`XLEN - 1: 0] pc;
wire [`XLEN - 1: 0] pc_next = pc + 4;
always @(posedge clock)
begin
if (reset)
begin
pc <= 64'h80000000 - 4;
end
else
begin
if (state != boot)
pc <= pc_next;
end
end
assign inst_sram_en = !reset;
assign inst_sram_wen = 0;
assign inst_sram_wdata = 0;
assign inst_sram_addr = pc_next[31: 0];
assign decodeStage = {
state == receive, // decodeStage.valid
pc, // decodeStage.pc
{32'b0, inst_sram_rdata} // decodeStage.inst
};
endmodule

@ -0,0 +1,12 @@
`include "mycpu.h"
module MemoryStage(
input clock,
input reset,
input [`EXE_MEM_WID - 1: 0] executeUnit,
output [`EXE_MEM_WID - 1: 0] memoryUnit
);
// TODO: MemoryStage
endmodule

@ -0,0 +1,14 @@
`include "mycpu.h"
module MemoryUnit(
// MemoryStage
input [`EXE_MEM_WID - 1: 0] memoryStage,
// WriteBackStage
output [`MEM_WB_WID - 1: 0] writeBackStage,
// memory sram
input [`XLEN - 1: 0] data_sram_rdata
);
// TODO: MemoryUnit
endmodule

@ -0,0 +1,80 @@
`include "mycpu.h"
//
module top(
input clock,
input reset,
// Interrupts
input mei, // to PLIC
input msi, // to CLINT
input mti, // to CLINT
input sei, // to PLIC
// inst sram interface
output inst_sram_en,
output [ 3: 0] inst_sram_wen,
output [31: 0] inst_sram_addr,
output [31: 0] inst_sram_wdata,
input [31: 0] inst_sram_rdata,
// data sram interface
output data_sram_en,
output [ 7: 0] data_sram_wen,
output [31: 0] data_sram_addr,
output [63: 0] data_sram_wdata,
input [63: 0] data_sram_rdata,
// trace debug interface
output debug_commit,
output [63: 0] debug_pc,
output [4: 0] debug_rf_wnum,
output [63: 0] debug_rf_wdata
);
//
//
//
// outports wire
wire [`IF_ID_WID - 1: 0] decodeStage;
FetchUnit u_FetchUnit(
.clock ( clock ),
.reset ( reset ),
.decodeStage ( decodeStage ),
.inst_sram_en ( inst_sram_en ),
.inst_sram_wen ( inst_sram_wen ),
.inst_sram_addr ( inst_sram_addr ),
.inst_sram_wdata ( inst_sram_wdata ),
.inst_sram_rdata ( inst_sram_rdata )
);
// outports wire
wire [`IF_ID_WID - 1: 0] decodeUnit;
DecoderStage u_DecoderStage(
.clock ( clock ),
.reset ( reset ),
.fetchUnit ( decodeStage ),
.decodeUnit ( decodeUnit )
);
// outports wire
wire [`XLEN - 1: 0] src1_rdata;
wire [`XLEN - 1: 0] src2_rdata;
// outports wire
wire [4: 0] src1_raddr;
wire [4: 0] src2_raddr;
wire [`ID_EXE_WID - 1: 0] executeStage;
DecodeUnit u_DecodeUnit(
.decodeStage ( decodeUnit ),
.src1_raddr ( src1_raddr ),
.src1_rdata ( src1_rdata ),
.src2_raddr ( src2_raddr ),
.src2_rdata ( src2_rdata ),
.executeStage ( executeStage )
);
// TODO:
endmodule

@ -0,0 +1,12 @@
`include "mycpu.h"
module WriteBackStage(
input clock,
input reset,
input [`MEM_WB_WID - 1: 0] memoryUnit,
output [`MEM_WB_WID - 1: 0] writeBackUnit
);
// TODO: WriteBackStage
endmodule

@ -0,0 +1,20 @@
`include "mycpu.h"
module WriteBackUnit(
input [`MEM_WB_WID - 1: 0] writeBackStage,
// ARegfile
output reg_wen,
output [4: 0] reg_waddr,
output [`XLEN - 1: 0] reg_wdata,
// debug
output debug_commit,
output [63: 0] debug_pc,
output [4: 0] debug_rf_wnum,
output [63: 0] debug_rf_wdata
);
//
//
// TODO: WriteBackUnit
endmodule
Loading…
Cancel
Save