mirror of
https://github.com/handsomezhuzhu/2025-yatcpu.git
synced 2026-02-20 20:10:14 +00:00
add mini-yatcpu
This commit is contained in:
11
README.md
11
README.md
@@ -1,6 +1,8 @@
|
||||
# YatCPU
|
||||
|
||||
本仓库由 [Tokisakix](https://github.com/Tokisakix)、[PurplePower](https://github.com/PurplePower)、[Han Huang](https://github.com/HHTheBest) 在 [2022-fall-yatcpu-repo](https://github.com/hrpccs/2022-fall-yatcpu-repo) 的基础上结合 2023 机组教学实情整理而来
|
||||
本仓库由 [Tokisakix](https://github.com/Tokisakix)、[PurplePower](https://github.com/PurplePower)、[Han Huang](https://github.com/HHTheBest) 在 [2022-fall-yatcpu-repo](https://github.com/hrpccs/2022-fall-yatcpu-repo) 的基础上结合 2023 机组教学实情整理而来,有较多原创内容
|
||||
|
||||
(PS: 能求个 star⭐ 吗 QAQ ~)
|
||||
|
||||
## 为什么需要本仓库?
|
||||
|
||||
@@ -68,6 +70,9 @@
|
||||
2. **使用一键烧板脚本**
|
||||
|
||||
> 此烧板脚本对任意方式配置的开发环境都有效,因为 vivado 的烧板跟开发环境是**相互独立**的,如果你使用 Dev Container 或 WSL 配置环境,你需要回到 Windows 下打开 PowerShell 进行烧板。
|
||||
> **此部分内容借鉴自 [YatCPU 的烧板验证](https://yatcpu.sysu.tech/getting-started/program-device/)**
|
||||
|
||||
原则上你可以在任意一个 lab 文件夹中使用下方的脚本进行烧板,下方的演示路径为 <code>2023-fall-yatcpu-repo/mini-yatcpu/</code>
|
||||
|
||||
**生成 Verilog 文件**
|
||||
|
||||
@@ -113,6 +118,4 @@
|
||||
## 外部参考链接
|
||||
- [YatCPU 文档地址](https://yatcpu.sysu.tech)
|
||||
- [YatCPU 的 Dev Container 环境配置](http://tokisakix.cn/2023/11/14/%5BDocker%5D%20YatCPU%20%E7%9A%84%20Dev%20container%20%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/)
|
||||
- [测试 Tokisakix 的烧板文件](https://blog.skyw.cc/archives/258.html)
|
||||
|
||||
(PS: 能求个 star⭐ 吗 QAQ ~)
|
||||
- [测试 Tokisakix 的烧板文件](https://blog.skyw.cc/archives/258.html)
|
||||
353
mini-yatcpu/.gitignore
vendored
Normal file
353
mini-yatcpu/.gitignore
vendored
Normal file
@@ -0,0 +1,353 @@
|
||||
### Project Specific stuff
|
||||
.sbt
|
||||
.cache
|
||||
test_run_dir/*
|
||||
**/__pycache__
|
||||
**/riscof_work
|
||||
### XilinxISE template
|
||||
# intermediate build files
|
||||
*.bgn
|
||||
*.bit
|
||||
*.bld
|
||||
*.cmd_log
|
||||
*.drc
|
||||
*.ll
|
||||
*.lso
|
||||
*.msd
|
||||
*.msk
|
||||
*.ncd
|
||||
*.ngc
|
||||
*.ngd
|
||||
*.ngr
|
||||
*.pad
|
||||
*.par
|
||||
*.pcf
|
||||
*.prj
|
||||
*.ptwx
|
||||
*.rbb
|
||||
*.rbd
|
||||
*.stx
|
||||
*.syr
|
||||
*.twr
|
||||
*.twx
|
||||
*.unroutes
|
||||
*.ut
|
||||
*.xpi
|
||||
*.xst
|
||||
*_bitgen.xwbt
|
||||
*_envsettings.html
|
||||
*_map.map
|
||||
*_map.mrp
|
||||
*_map.ngm
|
||||
*_map.xrpt
|
||||
*_ngdbuild.xrpt
|
||||
*_pad.csv
|
||||
*_pad.txt
|
||||
*_par.xrpt
|
||||
*_summary.html
|
||||
*_summary.xml
|
||||
*_usage.xml
|
||||
*_xst.xrpt
|
||||
|
||||
# project-wide generated files
|
||||
*.gise
|
||||
par_usage_statistics.html
|
||||
usage_statistics_webtalk.html
|
||||
webtalk.log
|
||||
webtalk_pn.xml
|
||||
|
||||
# generated folders
|
||||
iseconfig/
|
||||
xlnx_auto_0_xdb/
|
||||
xst/
|
||||
_ngo/
|
||||
_xmsgs/
|
||||
### Eclipse template
|
||||
*.pydevproject
|
||||
.metadata
|
||||
.gradle
|
||||
bin/
|
||||
tmp/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.settings/
|
||||
.loadpath
|
||||
|
||||
# Eclipse Core
|
||||
.project
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/
|
||||
|
||||
# Locally stored "Eclipse launch configurations"
|
||||
*.launch
|
||||
|
||||
# CDT-specific
|
||||
.cproject
|
||||
|
||||
# JDT-specific (Eclipse Java Development Tools)
|
||||
.classpath
|
||||
|
||||
# Java annotation processor (APT)
|
||||
.factorypath
|
||||
|
||||
# PDT-specific
|
||||
.buildpath
|
||||
|
||||
# sbteclipse plugin
|
||||
.target
|
||||
|
||||
# TeXlipse plugin
|
||||
.texlipse
|
||||
### C template
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
### SBT template
|
||||
# Simple Build Tool
|
||||
# http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html#configuring-version-control
|
||||
|
||||
target/
|
||||
lib_managed/
|
||||
src_managed/
|
||||
project/boot/
|
||||
.history
|
||||
.cache
|
||||
### Emacs template
|
||||
# -*- mode: gitignore; -*-
|
||||
*~
|
||||
\#*\#
|
||||
/.emacs.desktop
|
||||
/.emacs.desktop.lock
|
||||
*.elc
|
||||
auto-save-list
|
||||
tramp
|
||||
.\#*
|
||||
|
||||
# Org-mode
|
||||
.org-id-locations
|
||||
*_archive
|
||||
|
||||
# flymake-mode
|
||||
*_flymake.*
|
||||
|
||||
# eshell files
|
||||
/eshell/history
|
||||
/eshell/lastdir
|
||||
|
||||
# elpa packages
|
||||
/elpa/
|
||||
|
||||
# reftex files
|
||||
*.rel
|
||||
|
||||
# AUCTeX auto folder
|
||||
/auto/
|
||||
|
||||
# cask packages
|
||||
.cask/
|
||||
### Vim template
|
||||
[._]*.s[a-w][a-z]
|
||||
[._]s[a-w][a-z]
|
||||
*.un~
|
||||
Session.vim
|
||||
.netrwhist
|
||||
*~
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
|
||||
|
||||
*.iml
|
||||
|
||||
## Directory-based project format:
|
||||
.idea/
|
||||
# if you remove the above rule, at least ignore the following:
|
||||
|
||||
# User-specific stuff:
|
||||
# .idea/workspace.xml
|
||||
# .idea/tasks.xml
|
||||
# .idea/dictionaries
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
# .idea/dataSources.ids
|
||||
# .idea/dataSources.xml
|
||||
# .idea/sqlDataSources.xml
|
||||
# .idea/dynamic.xml
|
||||
# .idea/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
# .idea/gradle.xml
|
||||
# .idea/libraries
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
# .idea/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
### C++ template
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
### OSX template
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
### Xcode template
|
||||
# Xcode
|
||||
#
|
||||
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
|
||||
|
||||
## Build generated
|
||||
build/
|
||||
DerivedData
|
||||
|
||||
## Various settings
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata
|
||||
|
||||
## Other
|
||||
*.xccheckout
|
||||
*.moved-aside
|
||||
*.xcuserstate
|
||||
### Scala template
|
||||
*.class
|
||||
*.log
|
||||
/.bsp
|
||||
|
||||
# sbt specific
|
||||
.cache
|
||||
.history
|
||||
.lib/
|
||||
dist/*
|
||||
target/
|
||||
lib_managed/
|
||||
src_managed/
|
||||
project/boot/
|
||||
project/plugins/project/
|
||||
|
||||
# Scala-IDE specific
|
||||
.scala_dependencies
|
||||
.worksheet
|
||||
### Java template
|
||||
*.class
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
*.jou
|
||||
*.log
|
||||
.Xil
|
||||
vivado/basys3/riscv-basys3
|
||||
vivado/pynq/riscv-pynq
|
||||
vivado/pynq/NA
|
||||
.vscode
|
||||
.metals
|
||||
61
mini-yatcpu/Makefile
Normal file
61
mini-yatcpu/Makefile
Normal file
@@ -0,0 +1,61 @@
|
||||
# Copyright 2021 Howard Lau
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
test:
|
||||
sbt test
|
||||
|
||||
verilator:
|
||||
sbt "runMain board.verilator.VerilogGenerator"
|
||||
cd verilog/verilator && verilator --trace --exe --cc sim_main.cpp Top.v && make -C obj_dir -f VTop.mk
|
||||
|
||||
verilator-sim: verilator
|
||||
cd verilog/verilator && obj_dir/VTop $(SIM_TIME)
|
||||
|
||||
basys3:
|
||||
sbt "runMain board.basys3.VerilogGenerator"
|
||||
|
||||
pynq:
|
||||
sbt "runMain board.pynq.VerilogGenerator"
|
||||
|
||||
z710:
|
||||
sbt "runMain board.z710.VerilogGenerator"
|
||||
|
||||
bitstream-basys3: basys3
|
||||
cd vivado/basys3 && vivado -mode batch -source generate_bitstream.tcl
|
||||
|
||||
program-basys3: bitstream-basys3
|
||||
cd vivado/basys3 && vivado -mode batch -source program_device.tcl
|
||||
|
||||
vivado-sim-basys3: basys3
|
||||
cd vivado/basys3 && vivado -mode batch -source run_simulation.tcl
|
||||
|
||||
bitstream-pynq: pynq
|
||||
cd vivado/pynq && vivado -mode batch -source generate_bitstream.tcl
|
||||
|
||||
program-pynq: bitstream-pynq
|
||||
cd vivado/pynq && vivado -mode batch -source program_device.tcl
|
||||
|
||||
vivado-sim-pynq: pynq
|
||||
cd vivado/pynq && vivado -mode batch -source run_simulation.tcl
|
||||
|
||||
bitstream-z710: z710
|
||||
cd vivado/z710 && vivado -mode batch -source generate_bitstream.tcl
|
||||
|
||||
program-z710: bitstream-z710
|
||||
cd vivado/z710 && vivado -mode batch -source program_device.tcl
|
||||
|
||||
vivado-sim-z710: z710
|
||||
cd vivado/z710 && vivado -mode batch -source run_simulation.tcl
|
||||
|
||||
.PHONY: basys3 verilator z710 test bitstream program verilator-sim vivado-sim
|
||||
24
mini-yatcpu/build.sbt
Normal file
24
mini-yatcpu/build.sbt
Normal file
@@ -0,0 +1,24 @@
|
||||
import sbt.Keys.libraryDependencies
|
||||
// See README.md for license details.
|
||||
|
||||
ThisBuild / scalaVersion := "2.13.10"
|
||||
ThisBuild / version := "0.1.0"
|
||||
ThisBuild / organization := "io.github.howardlau1999"
|
||||
|
||||
val chiselVersion = "3.6.0"
|
||||
|
||||
lazy val root = (project in file("."))
|
||||
.settings(
|
||||
name := "yatcpu",
|
||||
libraryDependencies ++= Seq(
|
||||
"edu.berkeley.cs" %% "chisel3" % chiselVersion,
|
||||
"edu.berkeley.cs" %% "chiseltest" % "0.6.0" % "test",
|
||||
),
|
||||
scalacOptions ++= Seq(
|
||||
"-language:reflectiveCalls",
|
||||
"-deprecation",
|
||||
"-feature",
|
||||
"-Xcheckinit",
|
||||
),
|
||||
addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % chiselVersion cross CrossVersion.full),
|
||||
)
|
||||
1
mini-yatcpu/project/build.properties
Normal file
1
mini-yatcpu/project/build.properties
Normal file
@@ -0,0 +1 @@
|
||||
sbt.version = 1.9.6
|
||||
1
mini-yatcpu/project/plugins.sbt
Normal file
1
mini-yatcpu/project/plugins.sbt
Normal file
@@ -0,0 +1 @@
|
||||
logLevel := Level.Warn
|
||||
BIN
mini-yatcpu/src/main/resources/fibonacci.asmbin
Normal file
BIN
mini-yatcpu/src/main/resources/fibonacci.asmbin
Normal file
Binary file not shown.
BIN
mini-yatcpu/src/main/resources/hello.asmbin
Normal file
BIN
mini-yatcpu/src/main/resources/hello.asmbin
Normal file
Binary file not shown.
BIN
mini-yatcpu/src/main/resources/litenes.asmbin
Normal file
BIN
mini-yatcpu/src/main/resources/litenes.asmbin
Normal file
Binary file not shown.
BIN
mini-yatcpu/src/main/resources/mmio.asmbin
Normal file
BIN
mini-yatcpu/src/main/resources/mmio.asmbin
Normal file
Binary file not shown.
BIN
mini-yatcpu/src/main/resources/paging.asmbin
Normal file
BIN
mini-yatcpu/src/main/resources/paging.asmbin
Normal file
Binary file not shown.
BIN
mini-yatcpu/src/main/resources/quicksort.asmbin
Normal file
BIN
mini-yatcpu/src/main/resources/quicksort.asmbin
Normal file
Binary file not shown.
BIN
mini-yatcpu/src/main/resources/say_goodbye.asmbin
Normal file
BIN
mini-yatcpu/src/main/resources/say_goodbye.asmbin
Normal file
Binary file not shown.
BIN
mini-yatcpu/src/main/resources/sb.asmbin
Normal file
BIN
mini-yatcpu/src/main/resources/sb.asmbin
Normal file
Binary file not shown.
BIN
mini-yatcpu/src/main/resources/tetris.asmbin
Normal file
BIN
mini-yatcpu/src/main/resources/tetris.asmbin
Normal file
Binary file not shown.
BIN
mini-yatcpu/src/main/resources/tetris_mmu.asmbin
Normal file
BIN
mini-yatcpu/src/main/resources/tetris_mmu.asmbin
Normal file
Binary file not shown.
BIN
mini-yatcpu/src/main/resources/vga_font_8x16.bmp
Normal file
BIN
mini-yatcpu/src/main/resources/vga_font_8x16.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
52
mini-yatcpu/src/main/scala/board/basys3/BCD2Segments.scala
Normal file
52
mini-yatcpu/src/main/scala/board/basys3/BCD2Segments.scala
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package board.basys3
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class BCD2Segments extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val bcd = Input(UInt(4.W))
|
||||
val segs = Output(UInt(8.W))
|
||||
})
|
||||
|
||||
val bcd = io.bcd
|
||||
val segs = Wire(UInt(8.W))
|
||||
|
||||
segs := MuxLookup(bcd, 0xFF.U)(
|
||||
IndexedSeq(
|
||||
0.U -> "b10000001".U,
|
||||
1.U -> "b11001111".U,
|
||||
2.U -> "b10010010".U,
|
||||
3.U -> "b10000110".U,
|
||||
4.U -> "b11001100".U,
|
||||
5.U -> "b10100100".U,
|
||||
6.U -> "b10100000".U,
|
||||
7.U -> "b10001111".U,
|
||||
8.U -> "b10000000".U,
|
||||
9.U -> "b10000100".U,
|
||||
10.U -> "b00001000".U,
|
||||
11.U -> "b01100000".U,
|
||||
12.U -> "b00110001".U,
|
||||
13.U -> "b01000010".U,
|
||||
14.U -> "b00110000".U,
|
||||
15.U -> "b00111000".U,
|
||||
)
|
||||
)
|
||||
|
||||
io.segs := segs
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package board.basys3
|
||||
|
||||
import chisel3._
|
||||
|
||||
class OnboardDigitDisplay extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val digit_mask = Output(UInt(4.W))
|
||||
})
|
||||
|
||||
val counter = RegInit(UInt(16.W), 0.U)
|
||||
val digit_mask = RegInit(UInt(4.W), "b0111".U)
|
||||
|
||||
counter := counter + 1.U
|
||||
when(counter === 0.U) {
|
||||
digit_mask := (digit_mask << 1.U).asUInt + digit_mask(3)
|
||||
}
|
||||
io.digit_mask := digit_mask
|
||||
}
|
||||
33
mini-yatcpu/src/main/scala/board/basys3/SYSULogo.scala
Normal file
33
mini-yatcpu/src/main/scala/board/basys3/SYSULogo.scala
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package board.basys3
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class SYSULogo extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val digit_mask = Input(UInt(4.W))
|
||||
val segs = Output(UInt(8.W))
|
||||
})
|
||||
|
||||
io.segs := MuxLookup(io.digit_mask, "b00100100".U)(
|
||||
// "b0111".U, "b1101".U -> S
|
||||
IndexedSeq(
|
||||
"b1011".U -> "b01000100".U, // Y
|
||||
"b1110".U -> "b01000001".U, // U
|
||||
)
|
||||
)
|
||||
}
|
||||
41
mini-yatcpu/src/main/scala/board/basys3/SegmentMux.scala
Normal file
41
mini-yatcpu/src/main/scala/board/basys3/SegmentMux.scala
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package board.basys3
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class SegmentMux extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val digit_mask = Input(UInt(4.W))
|
||||
val numbers = Input(UInt(16.W))
|
||||
val segs = Output(UInt(8.W))
|
||||
})
|
||||
|
||||
|
||||
val digit = RegInit(UInt(4.W), 0.U)
|
||||
val bcd2segs = Module(new BCD2Segments)
|
||||
|
||||
bcd2segs.io.bcd := digit
|
||||
io.segs := bcd2segs.io.segs
|
||||
digit := MuxLookup(io.digit_mask, io.numbers(3, 0))(
|
||||
// "b1110".U
|
||||
IndexedSeq(
|
||||
"b1101".U -> io.numbers(7, 4),
|
||||
"b1011".U -> io.numbers(11, 8),
|
||||
"b0111".U -> io.numbers(15, 12)
|
||||
)
|
||||
)
|
||||
}
|
||||
142
mini-yatcpu/src/main/scala/board/basys3/Top.scala
Normal file
142
mini-yatcpu/src/main/scala/board/basys3/Top.scala
Normal file
@@ -0,0 +1,142 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package board.basys3
|
||||
|
||||
import bus.{BusArbiter, BusSwitch}
|
||||
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
|
||||
import chisel3.util._
|
||||
import chisel3.{ChiselEnum, _}
|
||||
import peripheral._
|
||||
import riscv._
|
||||
import riscv.core.CPU
|
||||
|
||||
object BootStates extends ChiselEnum {
|
||||
val Init, Loading, Finished = Value
|
||||
}
|
||||
|
||||
class Top extends Module {
|
||||
val binaryFilename = "tetris.asmbin"
|
||||
val io = IO(new Bundle {
|
||||
val switch = Input(UInt(16.W))
|
||||
|
||||
val segs = Output(UInt(8.W))
|
||||
val digit_mask = Output(UInt(4.W))
|
||||
|
||||
val hsync = Output(Bool())
|
||||
val vsync = Output(Bool())
|
||||
val rgb = Output(UInt(12.W))
|
||||
val led = Output(UInt(16.W))
|
||||
|
||||
val tx = Output(Bool())
|
||||
val rx = Input(Bool())
|
||||
})
|
||||
val boot_state = RegInit(BootStates.Init)
|
||||
|
||||
val uart = Module(new Uart(100000000, 115200))
|
||||
io.tx := uart.io.txd
|
||||
uart.io.rxd := io.rx
|
||||
|
||||
val cpu = Module(new CPU)
|
||||
val mem = Module(new Memory(Parameters.MemorySizeInWords))
|
||||
val timer = Module(new Timer)
|
||||
val dummy = Module(new DummySlave)
|
||||
val bus_arbiter = Module(new BusArbiter)
|
||||
val bus_switch = Module(new BusSwitch)
|
||||
|
||||
val instruction_rom = Module(new InstructionROM(binaryFilename))
|
||||
val rom_loader = Module(new ROMLoader(instruction_rom.capacity))
|
||||
|
||||
val vga_display = Module(new VGADisplay)
|
||||
vga_display.io.rgb := 0.U
|
||||
bus_arbiter.io.bus_request(0) := true.B
|
||||
|
||||
bus_switch.io.master <> cpu.io.axi4_channels
|
||||
bus_switch.io.address := cpu.io.bus_address
|
||||
for (i <- 0 until Parameters.SlaveDeviceCount) {
|
||||
bus_switch.io.slaves(i) <> dummy.io.channels
|
||||
}
|
||||
rom_loader.io.load_address := Parameters.EntryAddress
|
||||
rom_loader.io.load_start := false.B
|
||||
rom_loader.io.rom_data := instruction_rom.io.data
|
||||
instruction_rom.io.address := rom_loader.io.rom_address
|
||||
cpu.io.stall_flag_bus := true.B
|
||||
cpu.io.instruction_valid := false.B
|
||||
bus_switch.io.slaves(0) <> mem.io.channels
|
||||
rom_loader.io.channels <> dummy.io.channels
|
||||
switch(boot_state) {
|
||||
is(BootStates.Init) {
|
||||
rom_loader.io.load_start := true.B
|
||||
boot_state := BootStates.Loading
|
||||
rom_loader.io.channels <> mem.io.channels
|
||||
}
|
||||
is(BootStates.Loading) {
|
||||
rom_loader.io.load_start := false.B
|
||||
rom_loader.io.channels <> mem.io.channels
|
||||
when(rom_loader.io.load_finished) {
|
||||
boot_state := BootStates.Finished
|
||||
}
|
||||
}
|
||||
is(BootStates.Finished) {
|
||||
cpu.io.stall_flag_bus := false.B
|
||||
cpu.io.instruction_valid := true.B
|
||||
}
|
||||
}
|
||||
val display = Module(new CharacterDisplay)
|
||||
bus_switch.io.slaves(1) <> display.io.channels
|
||||
bus_switch.io.slaves(2) <> uart.io.channels
|
||||
bus_switch.io.slaves(4) <> timer.io.channels
|
||||
|
||||
cpu.io.interrupt_flag := Cat(uart.io.signal_interrupt, timer.io.signal_interrupt)
|
||||
|
||||
cpu.io.debug_read_address := 0.U
|
||||
mem.io.debug_read_address := 0.U
|
||||
|
||||
io.hsync := vga_display.io.hsync
|
||||
io.vsync := vga_display.io.vsync
|
||||
|
||||
display.io.x := vga_display.io.x
|
||||
display.io.y := vga_display.io.y
|
||||
display.io.video_on := vga_display.io.video_on
|
||||
|
||||
io.rgb := display.io.rgb
|
||||
|
||||
mem.io.debug_read_address := io.switch(15, 1).asUInt << 2
|
||||
io.led := Mux(
|
||||
io.switch(0),
|
||||
mem.io.debug_read_data(31, 16).asUInt,
|
||||
mem.io.debug_read_data(15, 0).asUInt,
|
||||
)
|
||||
|
||||
val onboard_display = Module(new OnboardDigitDisplay)
|
||||
io.digit_mask := onboard_display.io.digit_mask
|
||||
|
||||
val sysu_logo = Module(new SYSULogo)
|
||||
sysu_logo.io.digit_mask := io.digit_mask
|
||||
|
||||
val seg_mux = Module(new SegmentMux)
|
||||
seg_mux.io.digit_mask := io.digit_mask
|
||||
seg_mux.io.numbers := io.led
|
||||
|
||||
io.segs := MuxLookup(io.switch, seg_mux.io.segs)(
|
||||
IndexedSeq(
|
||||
0.U -> sysu_logo.io.segs
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
object VerilogGenerator extends App {
|
||||
(new ChiselStage).execute(Array("-X", "verilog", "-td", "verilog/basys3"), Seq(ChiselGeneratorAnnotation(() => new
|
||||
Top)))
|
||||
}
|
||||
149
mini-yatcpu/src/main/scala/board/pynq/Top.scala
Normal file
149
mini-yatcpu/src/main/scala/board/pynq/Top.scala
Normal file
@@ -0,0 +1,149 @@
|
||||
// Copyright 2022 Canbin Huang
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package board.pynq
|
||||
|
||||
import bus.{AXI4LiteChannels, AXI4LiteInterface, BusArbiter, BusSwitch}
|
||||
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
|
||||
import chisel3.util.{is, switch}
|
||||
import chisel3.{ChiselEnum, _}
|
||||
import peripheral._
|
||||
import riscv.Parameters
|
||||
import riscv.core.CPU
|
||||
|
||||
object BootStates extends ChiselEnum {
|
||||
val Init, Loading, BusWait, Finished = Value
|
||||
}
|
||||
|
||||
class Top extends Module {
|
||||
val binaryFilename = "litenes.asmbin"
|
||||
val io = IO(new Bundle() {
|
||||
val hdmi_clk_n = Output(Bool())
|
||||
val hdmi_clk_p = Output(Bool())
|
||||
val hdmi_data_n = Output(UInt(3.W))
|
||||
val hdmi_data_p = Output(UInt(3.W))
|
||||
val hdmi_hpdn = Output(Bool())
|
||||
|
||||
val axi_mem = new AXI4LiteInterface(32, 32)
|
||||
|
||||
val tx = Output(Bool())
|
||||
val rx = Input(Bool())
|
||||
|
||||
val led = Output(UInt(4.W))
|
||||
})
|
||||
val boot_state = RegInit(BootStates.Init)
|
||||
io.led := boot_state.asUInt
|
||||
val uart = Module(new Uart(125000000, 115200))
|
||||
io.tx := uart.io.txd
|
||||
uart.io.rxd := io.rx
|
||||
|
||||
val cpu = Module(new CPU)
|
||||
val mem = Wire(new AXI4LiteChannels(32, 32))
|
||||
val timer = Module(new Timer)
|
||||
val dummy = Module(new DummySlave)
|
||||
val bus_arbiter = Module(new BusArbiter)
|
||||
val bus_switch = Module(new BusSwitch)
|
||||
mem.write_address_channel.AWADDR <> io.axi_mem.AWADDR
|
||||
mem.write_address_channel.AWPROT <> io.axi_mem.AWPROT
|
||||
mem.write_address_channel.AWREADY <> io.axi_mem.AWREADY
|
||||
mem.write_address_channel.AWVALID <> io.axi_mem.AWVALID
|
||||
mem.read_address_channel.ARADDR <> io.axi_mem.ARADDR
|
||||
mem.read_address_channel.ARPROT <> io.axi_mem.ARPROT
|
||||
mem.read_address_channel.ARREADY <> io.axi_mem.ARREADY
|
||||
mem.read_address_channel.ARVALID <> io.axi_mem.ARVALID
|
||||
mem.read_data_channel.RDATA <> io.axi_mem.RDATA
|
||||
mem.read_data_channel.RVALID <> io.axi_mem.RVALID
|
||||
mem.read_data_channel.RRESP <> io.axi_mem.RRESP
|
||||
mem.read_data_channel.RREADY <> io.axi_mem.RREADY
|
||||
mem.write_data_channel.WDATA <> io.axi_mem.WDATA
|
||||
mem.write_data_channel.WVALID <> io.axi_mem.WVALID
|
||||
mem.write_data_channel.WSTRB <> io.axi_mem.WSTRB
|
||||
mem.write_data_channel.WREADY <> io.axi_mem.WREADY
|
||||
mem.write_response_channel.BVALID <> io.axi_mem.BVALID
|
||||
mem.write_response_channel.BRESP <> io.axi_mem.BRESP
|
||||
mem.write_response_channel.BREADY <> io.axi_mem.BREADY
|
||||
|
||||
val instruction_rom = Module(new InstructionROM(binaryFilename))
|
||||
val rom_loader = Module(new ROMLoader(instruction_rom.capacity))
|
||||
|
||||
val hdmi_display = Module(new HDMIDisplay)
|
||||
bus_arbiter.io.bus_request(0) := true.B
|
||||
|
||||
bus_switch.io.master <> cpu.io.axi4_channels
|
||||
bus_switch.io.address := cpu.io.bus_address
|
||||
for (i <- 0 until Parameters.SlaveDeviceCount) {
|
||||
bus_switch.io.slaves(i) <> dummy.io.channels
|
||||
}
|
||||
rom_loader.io.load_address := Parameters.EntryAddress
|
||||
rom_loader.io.load_start := false.B
|
||||
rom_loader.io.rom_data := instruction_rom.io.data
|
||||
instruction_rom.io.address := rom_loader.io.rom_address
|
||||
cpu.io.stall_flag_bus := true.B
|
||||
cpu.io.instruction_valid := false.B
|
||||
rom_loader.io.channels <> dummy.io.channels
|
||||
bus_switch.io.slaves(0) <> mem
|
||||
switch(boot_state) {
|
||||
is(BootStates.Init) {
|
||||
rom_loader.io.load_start := true.B
|
||||
boot_state := BootStates.Loading
|
||||
rom_loader.io.channels <> mem
|
||||
bus_switch.io.slaves(0) <> dummy.io.channels
|
||||
}
|
||||
is(BootStates.Loading) {
|
||||
rom_loader.io.load_start := false.B
|
||||
rom_loader.io.channels <> mem
|
||||
bus_switch.io.slaves(0) <> dummy.io.channels
|
||||
when(rom_loader.io.load_finished) {
|
||||
boot_state := BootStates.BusWait
|
||||
}
|
||||
}
|
||||
is(BootStates.BusWait) {
|
||||
when(!cpu.io.bus_busy) {
|
||||
boot_state := BootStates.Finished
|
||||
}
|
||||
}
|
||||
is(BootStates.Finished) {
|
||||
cpu.io.stall_flag_bus := false.B
|
||||
cpu.io.instruction_valid := true.B
|
||||
rom_loader.io.channels <> dummy.io.channels
|
||||
bus_switch.io.slaves(0) <> mem
|
||||
}
|
||||
}
|
||||
|
||||
val display = Module(new PixelDisplay)
|
||||
bus_switch.io.slaves(1) <> display.io.channels
|
||||
bus_switch.io.slaves(2) <> uart.io.channels
|
||||
bus_switch.io.slaves(4) <> timer.io.channels
|
||||
|
||||
cpu.io.interrupt_flag := uart.io.signal_interrupt ## timer.io.signal_interrupt
|
||||
io.led := uart.io.signal_interrupt ## timer.io.signal_interrupt ## boot_state.asUInt
|
||||
|
||||
cpu.io.debug_read_address := 0.U
|
||||
|
||||
display.io.x := hdmi_display.io.x_next
|
||||
display.io.y := hdmi_display.io.y_next
|
||||
display.io.video_on := hdmi_display.io.video_on
|
||||
hdmi_display.io.rgb := display.io.rgb
|
||||
|
||||
io.hdmi_hpdn := 1.U
|
||||
io.hdmi_data_n := hdmi_display.io.TMDSdata_n
|
||||
io.hdmi_data_p := hdmi_display.io.TMDSdata_p
|
||||
io.hdmi_clk_n := hdmi_display.io.TMDSclk_n
|
||||
io.hdmi_clk_p := hdmi_display.io.TMDSclk_p
|
||||
}
|
||||
|
||||
object VerilogGenerator extends App {
|
||||
(new ChiselStage).execute(Array("-X", "verilog", "-td", "verilog/pynq"), Seq(ChiselGeneratorAnnotation(() => new
|
||||
Top)))
|
||||
}
|
||||
71
mini-yatcpu/src/main/scala/board/verilator/Top.scala
Normal file
71
mini-yatcpu/src/main/scala/board/verilator/Top.scala
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright 2022 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package board.verilator
|
||||
|
||||
import bus.{AXI4LiteSlave, AXI4LiteSlaveBundle, BusArbiter, BusSwitch}
|
||||
import chisel3._
|
||||
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
|
||||
import peripheral.DummySlave
|
||||
import riscv.Parameters
|
||||
import riscv.core.CPU
|
||||
|
||||
class Top extends Module {
|
||||
|
||||
val io = IO(new Bundle {
|
||||
val signal_interrupt = Input(Bool())
|
||||
|
||||
val mem_slave = new AXI4LiteSlaveBundle(Parameters.AddrBits, Parameters.DataBits)
|
||||
val uart_slave = new AXI4LiteSlaveBundle(Parameters.AddrBits, Parameters.DataBits)
|
||||
|
||||
val cpu_debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val cpu_debug_read_data = Output(UInt(Parameters.DataWidth))
|
||||
})
|
||||
|
||||
// Memory is controlled in C++ code
|
||||
val mem_slave = Module(new AXI4LiteSlave(Parameters.AddrBits, Parameters.DataBits))
|
||||
io.mem_slave <> mem_slave.io.bundle
|
||||
|
||||
// UART is controlled in C++ code
|
||||
val uart_slave = Module(new AXI4LiteSlave(Parameters.AddrBits, Parameters.DataBits))
|
||||
io.uart_slave <> uart_slave.io.bundle
|
||||
|
||||
val cpu = Module(new CPU)
|
||||
val dummy = Module(new DummySlave)
|
||||
val bus_arbiter = Module(new BusArbiter)
|
||||
val bus_switch = Module(new BusSwitch)
|
||||
|
||||
bus_arbiter.io.bus_request(0) := true.B
|
||||
|
||||
bus_switch.io.master <> cpu.io.axi4_channels
|
||||
bus_switch.io.address := cpu.io.bus_address
|
||||
for (i <- 0 until Parameters.SlaveDeviceCount) {
|
||||
bus_switch.io.slaves(i) <> dummy.io.channels
|
||||
}
|
||||
|
||||
cpu.io.stall_flag_bus := false.B
|
||||
cpu.io.instruction_valid := true.B
|
||||
bus_switch.io.slaves(0) <> mem_slave.io.channels
|
||||
bus_switch.io.slaves(2) <> uart_slave.io.channels
|
||||
|
||||
cpu.io.interrupt_flag := io.signal_interrupt
|
||||
|
||||
cpu.io.debug_read_address := io.cpu_debug_read_address
|
||||
io.cpu_debug_read_data := cpu.io.debug_read_data
|
||||
}
|
||||
|
||||
object VerilogGenerator extends App {
|
||||
(new ChiselStage).execute(Array("-X", "verilog", "-td", "verilog/verilator"), Seq(ChiselGeneratorAnnotation(() =>
|
||||
new Top)))
|
||||
}
|
||||
119
mini-yatcpu/src/main/scala/board/z710/z710/Top.scala
Normal file
119
mini-yatcpu/src/main/scala/board/z710/z710/Top.scala
Normal file
@@ -0,0 +1,119 @@
|
||||
package board.z710
|
||||
|
||||
|
||||
import chisel3._
|
||||
import chisel3.stage.ChiselStage
|
||||
import chisel3.util._
|
||||
import chisel3.{ChiselEnum, _}
|
||||
|
||||
// import circt.stage.ChiselStage
|
||||
import chisel3.stage.ChiselGeneratorAnnotation
|
||||
|
||||
import bus._
|
||||
import peripheral._
|
||||
import riscv._
|
||||
import riscv.Parameters
|
||||
import riscv.core.CPU
|
||||
import javax.print.SimpleDoc
|
||||
|
||||
object BootStates extends ChiselEnum {
|
||||
val Init, Loading, BusWait, Finished = Value
|
||||
}
|
||||
|
||||
|
||||
class Top(binaryFilename: String ="say_goodbye.asmbin") extends Module {
|
||||
// val binaryFilename = "say_goodbye.asmbin"
|
||||
val io = IO(new Bundle {
|
||||
// val switch = Input(UInt(16.W))
|
||||
|
||||
// val rgb = Output(UInt(12.W))
|
||||
|
||||
val led = Output(Bool())
|
||||
val tx = Output(Bool())
|
||||
val rx = Input(Bool())
|
||||
|
||||
|
||||
})
|
||||
val boot_state = RegInit(BootStates.Init)
|
||||
|
||||
val uart = Module(new Uart(125_000_000, 115200)) // this freq is consistent with Zynq 7 PS UART module
|
||||
io.tx := uart.io.txd
|
||||
uart.io.rxd := io.rx
|
||||
|
||||
val cpu = Module(new CPU)
|
||||
val mem = Module(new Memory(Parameters.MemorySizeInWords))
|
||||
val timer = Module(new Timer)
|
||||
val dummy = Module(new DummySlave)
|
||||
val bus_arbiter = Module(new BusArbiter)
|
||||
val bus_switch = Module(new BusSwitch)
|
||||
|
||||
val instruction_rom = Module(new InstructionROM(binaryFilename))
|
||||
val rom_loader = Module(new ROMLoader(instruction_rom.capacity))
|
||||
|
||||
bus_arbiter.io.bus_request(0) := true.B
|
||||
|
||||
bus_switch.io.master <> cpu.io.axi4_channels
|
||||
bus_switch.io.address := cpu.io.bus_address
|
||||
for (i <- 0 until Parameters.SlaveDeviceCount) {
|
||||
bus_switch.io.slaves(i) <> dummy.io.channels
|
||||
}
|
||||
rom_loader.io.load_address := Parameters.EntryAddress
|
||||
rom_loader.io.load_start := false.B
|
||||
rom_loader.io.rom_data := instruction_rom.io.data
|
||||
instruction_rom.io.address := rom_loader.io.rom_address
|
||||
cpu.io.stall_flag_bus := true.B
|
||||
cpu.io.instruction_valid := false.B
|
||||
bus_switch.io.slaves(0) <> mem.io.channels
|
||||
rom_loader.io.channels <> dummy.io.channels
|
||||
switch(boot_state) {
|
||||
is(BootStates.Init) {
|
||||
rom_loader.io.load_start := true.B
|
||||
boot_state := BootStates.Loading
|
||||
rom_loader.io.channels <> mem.io.channels
|
||||
}
|
||||
is(BootStates.Loading) {
|
||||
rom_loader.io.load_start := false.B
|
||||
rom_loader.io.channels <> mem.io.channels
|
||||
when(rom_loader.io.load_finished) {
|
||||
boot_state := BootStates.Finished
|
||||
}
|
||||
}
|
||||
is(BootStates.Finished) {
|
||||
cpu.io.stall_flag_bus := false.B
|
||||
cpu.io.instruction_valid := true.B
|
||||
}
|
||||
}
|
||||
|
||||
bus_switch.io.slaves(2) <> uart.io.channels
|
||||
bus_switch.io.slaves(4) <> timer.io.channels
|
||||
|
||||
cpu.io.interrupt_flag := Cat(uart.io.signal_interrupt, timer.io.signal_interrupt)
|
||||
|
||||
cpu.io.debug_read_address := 0.U
|
||||
mem.io.debug_read_address := 0.U
|
||||
|
||||
|
||||
|
||||
val clock_freq = 100_000_000.U
|
||||
|
||||
val led_count = RegInit(0.U(32.W))
|
||||
when (led_count >= clock_freq) { // the led blinks every second, clock freq is 100M
|
||||
led_count := 0.U
|
||||
}.otherwise {
|
||||
led_count := led_count + 1.U
|
||||
}
|
||||
|
||||
io.led := (led_count >= (clock_freq >> 1))
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
object VerilogGenerator extends App {
|
||||
(new ChiselStage).execute(
|
||||
Array("-X", "verilog", "--target-dir", "verilog/z710"),
|
||||
Seq(ChiselGeneratorAnnotation(() => new Top())) // default bin file
|
||||
)
|
||||
|
||||
}
|
||||
312
mini-yatcpu/src/main/scala/bus/AXI4Lite.scala
Normal file
312
mini-yatcpu/src/main/scala/bus/AXI4Lite.scala
Normal file
@@ -0,0 +1,312 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package bus
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import riscv.Parameters
|
||||
|
||||
object AXI4Lite {
|
||||
val protWidth = 3
|
||||
val respWidth = 2
|
||||
}
|
||||
|
||||
class AXI4LiteWriteAddressChannel(addrWidth: Int) extends Bundle {
|
||||
|
||||
val AWVALID = Output(Bool())
|
||||
val AWREADY = Input(Bool())
|
||||
val AWADDR = Output(UInt(addrWidth.W))
|
||||
val AWPROT = Output(UInt(AXI4Lite.protWidth.W))
|
||||
|
||||
}
|
||||
|
||||
class AXI4LiteWriteDataChannel(dataWidth: Int) extends Bundle {
|
||||
val WVALID = Output(Bool())
|
||||
val WREADY = Input(Bool())
|
||||
val WDATA = Output(UInt(dataWidth.W))
|
||||
val WSTRB = Output(UInt((dataWidth / 8).W))
|
||||
}
|
||||
|
||||
class AXI4LiteWriteResponseChannel extends Bundle {
|
||||
val BVALID = Input(Bool())
|
||||
val BREADY = Output(Bool())
|
||||
val BRESP = Input(UInt(AXI4Lite.respWidth.W))
|
||||
}
|
||||
|
||||
class AXI4LiteReadAddressChannel(addrWidth: Int) extends Bundle {
|
||||
val ARVALID = Output(Bool())
|
||||
val ARREADY = Input(Bool())
|
||||
val ARADDR = Output(UInt(addrWidth.W))
|
||||
val ARPROT = Output(UInt(AXI4Lite.protWidth.W))
|
||||
}
|
||||
|
||||
class AXI4LiteReadDataChannel(dataWidth: Int) extends Bundle {
|
||||
val RVALID = Input(Bool())
|
||||
val RREADY = Output(Bool())
|
||||
val RDATA = Input(UInt(dataWidth.W))
|
||||
val RRESP = Input(UInt(AXI4Lite.respWidth.W))
|
||||
}
|
||||
|
||||
class AXI4LiteInterface(addrWidth: Int, dataWidth: Int) extends Bundle {
|
||||
val AWVALID = Output(Bool())
|
||||
val AWREADY = Input(Bool())
|
||||
val AWADDR = Output(UInt(addrWidth.W))
|
||||
val AWPROT = Output(UInt(AXI4Lite.protWidth.W))
|
||||
val WVALID = Output(Bool())
|
||||
val WREADY = Input(Bool())
|
||||
val WDATA = Output(UInt(dataWidth.W))
|
||||
val WSTRB = Output(UInt((dataWidth / 8).W))
|
||||
val BVALID = Input(Bool())
|
||||
val BREADY = Output(Bool())
|
||||
val BRESP = Input(UInt(AXI4Lite.respWidth.W))
|
||||
val ARVALID = Output(Bool())
|
||||
val ARREADY = Input(Bool())
|
||||
val ARADDR = Output(UInt(addrWidth.W))
|
||||
val ARPROT = Output(UInt(AXI4Lite.protWidth.W))
|
||||
val RVALID = Input(Bool())
|
||||
val RREADY = Output(Bool())
|
||||
val RDATA = Input(UInt(dataWidth.W))
|
||||
val RRESP = Input(UInt(AXI4Lite.respWidth.W))
|
||||
}
|
||||
|
||||
class AXI4LiteChannels(addrWidth: Int, dataWidth: Int) extends Bundle {
|
||||
val write_address_channel = new AXI4LiteWriteAddressChannel(addrWidth)
|
||||
val write_data_channel = new AXI4LiteWriteDataChannel(dataWidth)
|
||||
val write_response_channel = new AXI4LiteWriteResponseChannel()
|
||||
val read_address_channel = new AXI4LiteReadAddressChannel(addrWidth)
|
||||
val read_data_channel = new AXI4LiteReadDataChannel(dataWidth)
|
||||
}
|
||||
|
||||
class AXI4LiteSlaveBundle(addrWidth: Int, dataWidth: Int) extends Bundle {
|
||||
val read = Output(Bool())
|
||||
val write = Output(Bool())
|
||||
val read_data = Input(UInt(dataWidth.W))
|
||||
val read_valid = Input(Bool())
|
||||
val write_data = Output(UInt(dataWidth.W))
|
||||
val write_strobe = Output(Vec(Parameters.WordSize, Bool()))
|
||||
val address = Output(UInt(addrWidth.W))
|
||||
}
|
||||
|
||||
class AXI4LiteMasterBundle(addrWidth: Int, dataWidth: Int) extends Bundle {
|
||||
val read = Input(Bool())
|
||||
val write = Input(Bool())
|
||||
val read_data = Output(UInt(dataWidth.W))
|
||||
val write_data = Input(UInt(dataWidth.W))
|
||||
val write_strobe = Input(Vec(Parameters.WordSize, Bool()))
|
||||
val address = Input(UInt(addrWidth.W))
|
||||
|
||||
val busy = Output(Bool())
|
||||
val read_valid = Output(Bool())
|
||||
val write_valid = Output(Bool())
|
||||
}
|
||||
|
||||
object AXI4LiteStates extends ChiselEnum {
|
||||
val Idle, ReadAddr, ReadData, WriteAddr, WriteData, WriteResp = Value
|
||||
}
|
||||
|
||||
// TODO(howard): implement full duplex
|
||||
class AXI4LiteSlave(addrWidth: Int, dataWidth: Int) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val channels = Flipped(new AXI4LiteChannels(addrWidth, dataWidth))
|
||||
val bundle = new AXI4LiteSlaveBundle(addrWidth, dataWidth)
|
||||
})
|
||||
val state = RegInit(AXI4LiteStates.Idle)
|
||||
val addr = RegInit(0.U(dataWidth.W))
|
||||
io.bundle.address := addr
|
||||
val read = RegInit(false.B)
|
||||
io.bundle.read := read
|
||||
val write = RegInit(false.B)
|
||||
io.bundle.write := write
|
||||
val write_data = RegInit(0.U(dataWidth.W))
|
||||
io.bundle.write_data := write_data
|
||||
val write_strobe = RegInit(VecInit(Seq.fill(Parameters.WordSize)(false.B)))
|
||||
io.bundle.write_strobe := write_strobe
|
||||
|
||||
val ARREADY = RegInit(false.B)
|
||||
io.channels.read_address_channel.ARREADY := ARREADY
|
||||
val RVALID = RegInit(false.B)
|
||||
io.channels.read_data_channel.RVALID := RVALID
|
||||
val RRESP = RegInit(0.U(AXI4Lite.respWidth.W))
|
||||
io.channels.read_data_channel.RRESP := RRESP
|
||||
|
||||
io.channels.read_data_channel.RDATA := io.bundle.read_data
|
||||
|
||||
val AWREADY = RegInit(false.B)
|
||||
io.channels.write_address_channel.AWREADY := AWREADY
|
||||
val WREADY = RegInit(false.B)
|
||||
io.channels.write_data_channel.WREADY := WREADY
|
||||
write_data := io.channels.write_data_channel.WDATA
|
||||
val BVALID = RegInit(false.B)
|
||||
io.channels.write_response_channel.BVALID := BVALID
|
||||
val BRESP = WireInit(0.U(AXI4Lite.respWidth.W))
|
||||
io.channels.write_response_channel.BRESP := BRESP
|
||||
|
||||
switch(state) {
|
||||
is(AXI4LiteStates.Idle) {
|
||||
read := false.B
|
||||
write := false.B
|
||||
RVALID := false.B
|
||||
BVALID := false.B
|
||||
when(io.channels.write_address_channel.AWVALID) {
|
||||
state := AXI4LiteStates.WriteAddr
|
||||
}.elsewhen(io.channels.read_address_channel.ARVALID) {
|
||||
state := AXI4LiteStates.ReadAddr
|
||||
}
|
||||
}
|
||||
is(AXI4LiteStates.ReadAddr) {
|
||||
ARREADY := true.B
|
||||
when(io.channels.read_address_channel.ARVALID && ARREADY) {
|
||||
state := AXI4LiteStates.ReadData
|
||||
addr := io.channels.read_address_channel.ARADDR
|
||||
read := true.B
|
||||
ARREADY := false.B
|
||||
}
|
||||
}
|
||||
is(AXI4LiteStates.ReadData) {
|
||||
RVALID := io.bundle.read_valid
|
||||
when(io.channels.read_data_channel.RREADY && RVALID) {
|
||||
state := AXI4LiteStates.Idle
|
||||
RVALID := false.B
|
||||
}
|
||||
}
|
||||
is(AXI4LiteStates.WriteAddr) {
|
||||
AWREADY := true.B
|
||||
when(io.channels.write_address_channel.AWVALID && AWREADY) {
|
||||
addr := io.channels.write_address_channel.AWADDR
|
||||
state := AXI4LiteStates.WriteData
|
||||
AWREADY := false.B
|
||||
}
|
||||
}
|
||||
is(AXI4LiteStates.WriteData) {
|
||||
WREADY := true.B
|
||||
when(io.channels.write_data_channel.WVALID && WREADY) {
|
||||
state := AXI4LiteStates.WriteResp
|
||||
write_data := io.channels.write_data_channel.WDATA
|
||||
write_strobe := io.channels.write_data_channel.WSTRB.asBools
|
||||
write := true.B
|
||||
WREADY := false.B
|
||||
}
|
||||
}
|
||||
is(AXI4LiteStates.WriteResp) {
|
||||
WREADY := false.B
|
||||
BVALID := true.B
|
||||
when(io.channels.write_response_channel.BREADY && BVALID) {
|
||||
state := AXI4LiteStates.Idle
|
||||
write := false.B
|
||||
BVALID := false.B
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AXI4LiteMaster(addrWidth: Int, dataWidth: Int) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val channels = new AXI4LiteChannels(addrWidth, dataWidth)
|
||||
val bundle = new AXI4LiteMasterBundle(addrWidth, dataWidth)
|
||||
})
|
||||
val state = RegInit(AXI4LiteStates.Idle)
|
||||
io.bundle.busy := state =/= AXI4LiteStates.Idle
|
||||
|
||||
val addr = RegInit(0.U(dataWidth.W))
|
||||
val read_valid = RegInit(false.B)
|
||||
io.bundle.read_valid := read_valid
|
||||
val write_valid = RegInit(false.B)
|
||||
io.bundle.write_valid := write_valid
|
||||
val write_data = RegInit(0.U(dataWidth.W))
|
||||
val write_strobe = RegInit(VecInit(Seq.fill(Parameters.WordSize)(false.B)))
|
||||
val read_data = RegInit(0.U(dataWidth.W))
|
||||
|
||||
io.channels.read_address_channel.ARADDR := 0.U
|
||||
val ARVALID = RegInit(false.B)
|
||||
io.channels.read_address_channel.ARVALID := ARVALID
|
||||
io.channels.read_address_channel.ARPROT := 0.U
|
||||
val RREADY = RegInit(false.B)
|
||||
io.channels.read_data_channel.RREADY := RREADY
|
||||
|
||||
io.bundle.read_data := io.channels.read_data_channel.RDATA
|
||||
val AWVALID = RegInit(false.B)
|
||||
io.channels.write_address_channel.AWADDR := 0.U
|
||||
io.channels.write_address_channel.AWVALID := AWVALID
|
||||
val WVALID = RegInit(false.B)
|
||||
io.channels.write_data_channel.WVALID := WVALID
|
||||
io.channels.write_data_channel.WDATA := write_data
|
||||
io.channels.write_address_channel.AWPROT := 0.U
|
||||
io.channels.write_data_channel.WSTRB := write_strobe.asUInt
|
||||
val BREADY = RegInit(false.B)
|
||||
io.channels.write_response_channel.BREADY := BREADY
|
||||
|
||||
switch(state) {
|
||||
is(AXI4LiteStates.Idle) {
|
||||
WVALID := false.B
|
||||
AWVALID := false.B
|
||||
ARVALID := false.B
|
||||
RREADY := false.B
|
||||
read_valid := false.B
|
||||
write_valid := false.B
|
||||
when(io.bundle.write) {
|
||||
state := AXI4LiteStates.WriteAddr
|
||||
addr := io.bundle.address
|
||||
write_data := io.bundle.write_data
|
||||
write_strobe := io.bundle.write_strobe
|
||||
}.elsewhen(io.bundle.read) {
|
||||
state := AXI4LiteStates.ReadAddr
|
||||
addr := io.bundle.address
|
||||
}
|
||||
}
|
||||
is(AXI4LiteStates.ReadAddr) {
|
||||
ARVALID := true.B
|
||||
io.channels.read_address_channel.ARADDR := addr
|
||||
when(io.channels.read_address_channel.ARREADY && ARVALID) {
|
||||
state := AXI4LiteStates.ReadData
|
||||
io.channels.read_address_channel.ARADDR := addr
|
||||
ARVALID := false.B
|
||||
}
|
||||
}
|
||||
is(AXI4LiteStates.ReadData) {
|
||||
when(io.channels.read_data_channel.RVALID && io.channels.read_data_channel.RRESP === 0.U) {
|
||||
state := AXI4LiteStates.Idle
|
||||
read_valid := true.B
|
||||
RREADY := true.B
|
||||
read_data := io.channels.read_data_channel.RDATA
|
||||
}
|
||||
}
|
||||
is(AXI4LiteStates.WriteAddr) {
|
||||
AWVALID := true.B
|
||||
io.channels.write_address_channel.AWADDR := addr
|
||||
when(io.channels.write_address_channel.AWREADY && AWVALID) {
|
||||
state := AXI4LiteStates.WriteData
|
||||
io.channels.write_address_channel.AWADDR := addr
|
||||
AWVALID := false.B
|
||||
}
|
||||
}
|
||||
is(AXI4LiteStates.WriteData) {
|
||||
WVALID := true.B
|
||||
io.channels.write_address_channel.AWADDR := addr
|
||||
when(io.channels.write_data_channel.WREADY && WVALID) {
|
||||
io.channels.write_address_channel.AWADDR := addr
|
||||
state := AXI4LiteStates.WriteResp
|
||||
WVALID := false.B
|
||||
}
|
||||
}
|
||||
is(AXI4LiteStates.WriteResp) {
|
||||
BREADY := true.B
|
||||
when(io.channels.write_response_channel.BVALID && BREADY) {
|
||||
state := AXI4LiteStates.Idle
|
||||
write_valid := true.B
|
||||
BREADY := false.B
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
40
mini-yatcpu/src/main/scala/bus/BusArbiter.scala
Normal file
40
mini-yatcpu/src/main/scala/bus/BusArbiter.scala
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package bus
|
||||
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
|
||||
class BusArbiter extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val bus_request = Input(Vec(Parameters.MasterDeviceCount, Bool()))
|
||||
val bus_granted = Output(Vec(Parameters.MasterDeviceCount, Bool()))
|
||||
|
||||
val ctrl_stall_flag = Output(Bool())
|
||||
})
|
||||
val granted = Wire(UInt())
|
||||
// Static Priority Arbitration
|
||||
// Higher number = Higher priority
|
||||
granted := 0.U
|
||||
for (i <- 0 until Parameters.MasterDeviceCount) {
|
||||
when(io.bus_request(i.U)) {
|
||||
granted := i.U
|
||||
}
|
||||
}
|
||||
for (i <- 0 until Parameters.MasterDeviceCount) {
|
||||
io.bus_granted(i.U) := i.U === granted
|
||||
}
|
||||
io.ctrl_stall_flag := !io.bus_granted(0.U)
|
||||
}
|
||||
33
mini-yatcpu/src/main/scala/bus/BusSwitch.scala
Normal file
33
mini-yatcpu/src/main/scala/bus/BusSwitch.scala
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package bus
|
||||
|
||||
import chisel3._
|
||||
import peripheral.DummyMaster
|
||||
import riscv.Parameters
|
||||
|
||||
class BusSwitch extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val address = Input(UInt(Parameters.AddrWidth))
|
||||
val slaves = Vec(Parameters.SlaveDeviceCount, new AXI4LiteChannels(Parameters.AddrBits, Parameters.DataBits))
|
||||
val master = Flipped(new AXI4LiteChannels(Parameters.AddrBits, Parameters.DataBits))
|
||||
})
|
||||
val dummy = Module(new DummyMaster)
|
||||
val index = io.address(Parameters.AddrBits - 1, Parameters.AddrBits - Parameters.SlaveDeviceCountBits)
|
||||
for (i <- 0 until Parameters.SlaveDeviceCount) {
|
||||
io.slaves(i) <> dummy.io.channels
|
||||
}
|
||||
io.master <> io.slaves(index)
|
||||
}
|
||||
86
mini-yatcpu/src/main/scala/peripheral/CharacterDisplay.scala
Normal file
86
mini-yatcpu/src/main/scala/peripheral/CharacterDisplay.scala
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright 2022 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package peripheral
|
||||
|
||||
import bus.{AXI4LiteChannels, AXI4LiteSlave}
|
||||
import chisel3.util.{MuxLookup, log2Up}
|
||||
import chisel3.{Bool, Bundle, Flipped, Module, Mux, Output, UInt, Wire, _}
|
||||
import peripheral.ScreenInfo.{DisplayHorizontal, DisplayVertical}
|
||||
import riscv.Parameters
|
||||
|
||||
object GlyphInfo {
|
||||
val glyphWidth = 8
|
||||
val glyphHeight = 16
|
||||
// ASCII printable characters start from here
|
||||
val spaceIndex = 1
|
||||
}
|
||||
|
||||
object ScreenInfo {
|
||||
val DisplayHorizontal = 640
|
||||
val DisplayVertical = 480
|
||||
}
|
||||
|
||||
object CharacterBufferInfo {
|
||||
val CharCols = DisplayHorizontal / GlyphInfo.glyphWidth
|
||||
val CharRows = DisplayVertical / GlyphInfo.glyphHeight
|
||||
val Chars = CharCols * CharRows
|
||||
}
|
||||
|
||||
class CharacterDisplay extends Module {
|
||||
val io = IO(new Bundle() {
|
||||
val channels = Flipped(new AXI4LiteChannels(log2Up(CharacterBufferInfo.Chars), Parameters.DataBits))
|
||||
|
||||
val x = Input(UInt(16.W))
|
||||
val y = Input(UInt(16.W))
|
||||
val video_on = Input(Bool())
|
||||
|
||||
val rgb = Output(UInt(24.W))
|
||||
})
|
||||
val slave = Module(new AXI4LiteSlave(log2Up(CharacterBufferInfo.Chars), Parameters.DataBits))
|
||||
slave.io.channels <> io.channels
|
||||
val mem = Module(new BlockRAM(CharacterBufferInfo.Chars / Parameters.WordSize))
|
||||
slave.io.bundle.read_valid := true.B
|
||||
mem.io.write_enable := slave.io.bundle.write
|
||||
mem.io.write_data := slave.io.bundle.write_data
|
||||
mem.io.write_address := slave.io.bundle.address
|
||||
mem.io.write_strobe := slave.io.bundle.write_strobe
|
||||
|
||||
mem.io.read_address := slave.io.bundle.address
|
||||
slave.io.bundle.read_data := mem.io.read_data
|
||||
|
||||
|
||||
val font_rom = Module(new FontROM)
|
||||
val row = (io.y >> log2Up(GlyphInfo.glyphHeight)).asUInt
|
||||
val col = (io.x >> log2Up(GlyphInfo.glyphWidth)).asUInt
|
||||
val char_index = (row * CharacterBufferInfo.CharCols.U) + col
|
||||
val offset = char_index(1, 0)
|
||||
val ch = Wire(UInt(8.W))
|
||||
|
||||
mem.io.debug_read_address := char_index
|
||||
ch := MuxLookup(offset, 0.U)(
|
||||
IndexedSeq(
|
||||
0.U -> mem.io.debug_read_data(7, 0).asUInt,
|
||||
1.U -> mem.io.debug_read_data(15, 8).asUInt,
|
||||
2.U -> mem.io.debug_read_data(23, 16).asUInt,
|
||||
3.U -> mem.io.debug_read_data(31, 24).asUInt
|
||||
)
|
||||
)
|
||||
font_rom.io.glyph_index := Mux(ch >= 32.U, ch - 31.U, 0.U)
|
||||
font_rom.io.glyph_y := io.y(log2Up(GlyphInfo.glyphHeight) - 1, 0)
|
||||
|
||||
// White if pixel_on and glyph pixel on
|
||||
val glyph_x = io.x(log2Up(GlyphInfo.glyphWidth) - 1, 0)
|
||||
io.rgb := Mux(io.video_on && font_rom.io.glyph_pixel_byte(glyph_x), 0xFFFFFF.U, 0.U)
|
||||
}
|
||||
33
mini-yatcpu/src/main/scala/peripheral/DummyMaster.scala
Normal file
33
mini-yatcpu/src/main/scala/peripheral/DummyMaster.scala
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package peripheral
|
||||
|
||||
import bus.{AXI4LiteChannels, AXI4LiteMaster}
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
|
||||
// A dummy master that never initiates reads or writes
|
||||
class DummyMaster extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val channels = new AXI4LiteChannels(Parameters.AddrBits, Parameters.DataBits)
|
||||
})
|
||||
val master = Module(new AXI4LiteMaster(Parameters.AddrBits, Parameters.DataBits))
|
||||
master.io.channels <> io.channels
|
||||
master.io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B))
|
||||
master.io.bundle.write_data := 0.U
|
||||
master.io.bundle.write := false.B
|
||||
master.io.bundle.read := false.B
|
||||
master.io.bundle.address := 0.U
|
||||
}
|
||||
32
mini-yatcpu/src/main/scala/peripheral/DummySlave.scala
Normal file
32
mini-yatcpu/src/main/scala/peripheral/DummySlave.scala
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package peripheral
|
||||
|
||||
import bus.{AXI4LiteChannels, AXI4LiteSlave}
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
|
||||
// A dummy AXI4 slave that only returns 0 on read
|
||||
// and ignores all writes
|
||||
class DummySlave extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val channels = Flipped(new AXI4LiteChannels(4, Parameters.DataBits))
|
||||
})
|
||||
|
||||
val slave = Module(new AXI4LiteSlave(Parameters.AddrBits, Parameters.DataBits))
|
||||
slave.io.channels <> io.channels
|
||||
slave.io.bundle.read_valid := true.B
|
||||
slave.io.bundle.read_data := 0xDEADBEEFL.U
|
||||
}
|
||||
64
mini-yatcpu/src/main/scala/peripheral/FontROM.scala
Normal file
64
mini-yatcpu/src/main/scala/peripheral/FontROM.scala
Normal file
@@ -0,0 +1,64 @@
|
||||
package peripheral
|
||||
|
||||
import chisel3.experimental.{ChiselAnnotation, annotate}
|
||||
import chisel3.util.experimental.loadMemoryFromFileInline
|
||||
import chisel3.{Bundle, Input, Module, Output, SyncReadMem, UInt, _}
|
||||
import firrtl.annotations.MemorySynthInit
|
||||
|
||||
import java.io.FileWriter
|
||||
import java.nio.file.Paths
|
||||
import javax.imageio.ImageIO
|
||||
|
||||
class FontROM(fontBitmapFilename: String = "vga_font_8x16.bmp") extends Module {
|
||||
val glyphWidth = GlyphInfo.glyphWidth
|
||||
val glyphHeight = GlyphInfo.glyphHeight
|
||||
|
||||
val io = IO(new Bundle {
|
||||
val glyph_index = Input(UInt(7.W))
|
||||
val glyph_y = Input(UInt(4.W))
|
||||
|
||||
val glyph_pixel_byte = Output(UInt(8.W))
|
||||
})
|
||||
|
||||
annotate(new ChiselAnnotation {
|
||||
override def toFirrtl =
|
||||
MemorySynthInit
|
||||
})
|
||||
|
||||
val (hexTxtPath, glyphCount) = readFontBitmap()
|
||||
val mem = SyncReadMem(glyphCount, UInt(8.W))
|
||||
loadMemoryFromFileInline(mem, hexTxtPath.toString.replaceAll("\\\\", "/"))
|
||||
io.glyph_pixel_byte := mem.read(io.glyph_index * GlyphInfo.glyphHeight.U + io.glyph_y, true.B)
|
||||
|
||||
def readFontBitmap() = {
|
||||
val inputStream = getClass.getClassLoader.getResourceAsStream(fontBitmapFilename)
|
||||
val image = ImageIO.read(inputStream)
|
||||
|
||||
val glyphColumns = image.getWidth() / glyphWidth
|
||||
val glyphRows = image.getHeight / glyphHeight
|
||||
val glyphCount = glyphColumns * glyphRows
|
||||
val glyphs = new Array[UInt](glyphCount * GlyphInfo.glyphHeight)
|
||||
|
||||
for (row <- 0 until glyphRows) {
|
||||
for (col <- 0 until glyphColumns) {
|
||||
for (i <- 0 until glyphHeight) {
|
||||
var lineInt = 0
|
||||
for (j <- 0 until glyphWidth) {
|
||||
if (image.getRGB(col * glyphWidth + j, row * glyphHeight + i) != 0xFFFFFFFF) {
|
||||
lineInt |= (1 << j)
|
||||
}
|
||||
}
|
||||
glyphs((row * glyphColumns + col) * GlyphInfo.glyphHeight + i) = lineInt.U(8.W)
|
||||
}
|
||||
}
|
||||
}
|
||||
val currentDir = System.getProperty("user.dir")
|
||||
val hexTxtPath = Paths.get(currentDir, "verilog", f"${fontBitmapFilename}.txt")
|
||||
val writer = new FileWriter(hexTxtPath.toString)
|
||||
for (i <- glyphs.indices) {
|
||||
writer.write(f"@$i%x\n${glyphs(i).litValue}%02x\n")
|
||||
}
|
||||
writer.close()
|
||||
(hexTxtPath, glyphs.length)
|
||||
}
|
||||
}
|
||||
389
mini-yatcpu/src/main/scala/peripheral/HDMIDisplay.scala
Normal file
389
mini-yatcpu/src/main/scala/peripheral/HDMIDisplay.scala
Normal file
@@ -0,0 +1,389 @@
|
||||
// Copyright 2022 hrpccs
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package peripheral
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class HDMISync extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val hsync = Output(Bool())
|
||||
val vsync = Output(Bool())
|
||||
val video_on = Output(Bool())
|
||||
val p_tick = Output(Bool())
|
||||
val f_tick = Output(Bool())
|
||||
val x = Output(UInt(10.W))
|
||||
val y = Output(UInt(10.W))
|
||||
val x_next = Output(UInt(10.W))
|
||||
val y_next = Output(UInt(10.W))
|
||||
})
|
||||
|
||||
val DisplayHorizontal = ScreenInfo.DisplayHorizontal
|
||||
val DisplayVertical = ScreenInfo.DisplayVertical
|
||||
|
||||
val BorderLeft = 48
|
||||
val BorderRight = 16
|
||||
val BorderTop = 10
|
||||
val BorderBottom = 33
|
||||
|
||||
val RetraceHorizontal = 96
|
||||
val RetraceVertical = 2
|
||||
|
||||
val MaxHorizontal = DisplayHorizontal + BorderLeft + BorderRight + RetraceHorizontal - 1
|
||||
val MaxVertical = DisplayVertical + BorderTop + BorderBottom + RetraceVertical - 1
|
||||
|
||||
val RetraceHorizontalStart = DisplayHorizontal + BorderRight
|
||||
val RetraceHorizontalEnd = RetraceHorizontalStart + RetraceHorizontal - 1
|
||||
|
||||
val RetraceVerticalStart = DisplayVertical + BorderBottom
|
||||
val RetraceVerticalEnd = RetraceVerticalStart + RetraceVertical - 1
|
||||
|
||||
val pixel = RegInit(UInt(3.W), 0.U)
|
||||
val pixel_next = Wire(UInt(3.W))
|
||||
val pixel_tick = Wire(Bool())
|
||||
|
||||
val v_count_reg = RegInit(UInt(10.W), 0.U)
|
||||
val h_count_reg = RegInit(UInt(10.W), 0.U)
|
||||
|
||||
val v_count_next = Wire(UInt(10.W))
|
||||
val h_count_next = Wire(UInt(10.W))
|
||||
|
||||
val vsync_reg = RegInit(Bool(), false.B)
|
||||
val hsync_reg = RegInit(Bool(), false.B)
|
||||
|
||||
val vsync_next = Wire(Bool())
|
||||
val hsync_next = Wire(Bool())
|
||||
|
||||
pixel_next := Mux(pixel === 4.U, 0.U, pixel + 1.U)
|
||||
pixel_tick := pixel === 0.U
|
||||
|
||||
h_count_next := Mux(
|
||||
pixel_tick,
|
||||
Mux(h_count_reg === MaxHorizontal.U, 0.U, h_count_reg + 1.U),
|
||||
h_count_reg
|
||||
)
|
||||
|
||||
v_count_next := Mux(
|
||||
pixel_tick && h_count_reg === MaxHorizontal.U,
|
||||
Mux(v_count_reg === MaxVertical.U, 0.U, v_count_reg + 1.U),
|
||||
v_count_reg
|
||||
)
|
||||
|
||||
hsync_next := h_count_reg >= RetraceHorizontalStart.U && h_count_reg <= RetraceHorizontalEnd.U
|
||||
vsync_next := v_count_reg >= RetraceVerticalStart.U && v_count_reg <= RetraceVerticalEnd.U
|
||||
|
||||
pixel := pixel_next
|
||||
hsync_reg := hsync_next
|
||||
vsync_reg := vsync_next
|
||||
v_count_reg := v_count_next
|
||||
h_count_reg := h_count_next
|
||||
|
||||
io.video_on := h_count_reg < DisplayHorizontal.U && v_count_reg < DisplayVertical.U
|
||||
io.hsync := hsync_reg
|
||||
io.vsync := vsync_reg
|
||||
io.x := h_count_reg
|
||||
io.y := v_count_reg
|
||||
io.x_next := h_count_next
|
||||
io.y_next := v_count_next
|
||||
io.p_tick := pixel_tick
|
||||
io.f_tick := io.x === 0.U && io.y === 0.U
|
||||
}
|
||||
|
||||
class TMDS_encoder extends Module {
|
||||
val io = IO(new Bundle() {
|
||||
val video_data = Input(UInt(8.W)) //r,g,b,8bit
|
||||
val control_data = Input(UInt(2.W))
|
||||
val video_on = Input(Bool())
|
||||
val TMDS = Output(UInt(10.W))
|
||||
})
|
||||
val Nb1s = PopCount(io.video_data)
|
||||
val xored = xorfct(io.video_data)
|
||||
val xnored = xnorfct(io.video_data)
|
||||
val XNOR = (Nb1s > 4.U(4.W)) || (Nb1s === 4.U(4.W) && io.video_data(0) === 0.U)
|
||||
val q_m = RegInit(0.U(9.W))
|
||||
val diffSize = 4
|
||||
val diff = RegInit(0.S(diffSize.W))
|
||||
q_m := Mux(
|
||||
XNOR,
|
||||
xnored,
|
||||
xored
|
||||
)
|
||||
val disparitySize = 4
|
||||
val disparityReg = RegInit(0.S(disparitySize.W))
|
||||
diff := PopCount(q_m).asSInt - 4.S
|
||||
val doutReg = RegInit("b1010101011".U(10.W))
|
||||
|
||||
def xorfct(value: UInt): UInt = {
|
||||
val vin = VecInit(value.asBools)
|
||||
val res = VecInit(511.U.asBools)
|
||||
res(0) := vin(0)
|
||||
for (i <- 1 to 7) {
|
||||
res(i) := res(i - 1) ^ vin(i)
|
||||
}
|
||||
res(8) := 1.U
|
||||
res.asUInt
|
||||
}
|
||||
|
||||
def xnorfct(value: UInt): UInt = {
|
||||
val vin = VecInit(value.asBools)
|
||||
val res = VecInit(511.U.asBools)
|
||||
res(0) := vin(0)
|
||||
for (i <- 1 to 7) {
|
||||
res(i) := !(res(i - 1) ^ vin(i))
|
||||
}
|
||||
res(8) := 0.U
|
||||
res.asUInt
|
||||
}
|
||||
|
||||
when(io.video_on === false.B) {
|
||||
disparityReg := 0.S
|
||||
doutReg := "b1010101011".U(10.W)
|
||||
switch(io.control_data) {
|
||||
is("b00".U(2.W)) {
|
||||
doutReg := "b1101010100".U(10.W)
|
||||
}
|
||||
is("b01".U(2.W)) {
|
||||
doutReg := "b0010101011".U(10.W)
|
||||
}
|
||||
is("b10".U(2.W)) {
|
||||
doutReg := "b0101010100".U(10.W)
|
||||
}
|
||||
}
|
||||
}.otherwise {
|
||||
when(disparityReg === 0.S || diff === 0.S) {
|
||||
when(q_m(8) === false.B) {
|
||||
doutReg := "b10".U(2.W) ## ~q_m(7, 0)
|
||||
disparityReg := disparityReg - diff
|
||||
}.otherwise {
|
||||
doutReg := "b01".U(2.W) ## q_m(7, 0)
|
||||
disparityReg := disparityReg + diff
|
||||
}
|
||||
}.elsewhen((!diff(diffSize - 1) && !disparityReg(disparitySize - 1))
|
||||
|| (diff(diffSize - 1) && disparityReg(disparitySize - 1))) {
|
||||
doutReg := 1.U(1.W) ## q_m(8) ## ~q_m(7, 0)
|
||||
when(q_m(8)) {
|
||||
disparityReg := disparityReg + 1.S - diff
|
||||
}.otherwise {
|
||||
disparityReg := disparityReg - diff
|
||||
}
|
||||
}.otherwise {
|
||||
doutReg := 0.U(1.W) ## q_m
|
||||
when(q_m(8)) {
|
||||
disparityReg := disparityReg + diff
|
||||
}.otherwise {
|
||||
disparityReg := disparityReg - 1.S + diff
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
io.TMDS := doutReg
|
||||
}
|
||||
|
||||
class HDMIDisplay extends Module {
|
||||
val io = IO(new Bundle() {
|
||||
val rgb = Input(UInt(24.W))
|
||||
val x = Output(UInt(16.W))
|
||||
val y = Output(UInt(16.W))
|
||||
val x_next = Output(UInt(16.W))
|
||||
val y_next = Output(UInt(16.W))
|
||||
val video_on = Output(Bool())
|
||||
|
||||
val TMDSclk_p = Output(Bool())
|
||||
val TMDSdata_p = Output(UInt(3.W))
|
||||
val TMDSclk_n = Output(Bool())
|
||||
val TMDSdata_n = Output(UInt(3.W))
|
||||
})
|
||||
val rgb = io.rgb
|
||||
val pixel_clk = Wire(Bool())
|
||||
val hsync = Wire(Bool())
|
||||
val vsync = Wire(Bool())
|
||||
val sync = Module(new HDMISync)
|
||||
|
||||
io.x := sync.io.x
|
||||
io.y := sync.io.y
|
||||
io.x_next := sync.io.x_next
|
||||
io.y_next := sync.io.y_next
|
||||
io.video_on := sync.io.video_on
|
||||
|
||||
hsync := sync.io.hsync
|
||||
vsync := sync.io.vsync
|
||||
pixel_clk := sync.io.p_tick
|
||||
|
||||
// TMDS_PLLVR is a vivado IP core, check it in /verilog/pynq/TMDS_PLLVR.v
|
||||
val serial_clk = Wire(Clock())
|
||||
val pll_lock = Wire(Bool())
|
||||
val tmdspll = Module(new TMDS_PLLVR)
|
||||
val rst = Wire(Reset())
|
||||
tmdspll.io.clkin := pixel_clk.asClock
|
||||
serial_clk := tmdspll.io.clkout
|
||||
pll_lock := tmdspll.io.lock
|
||||
tmdspll.io.reset := reset
|
||||
rst := ~pll_lock
|
||||
|
||||
val tmds = Wire(UInt(3.W))
|
||||
val tmds_clk = Wire(Bool())
|
||||
withClockAndReset(pixel_clk.asClock, rst) {
|
||||
val tmds_channel1 = Wire(UInt(10.W))
|
||||
val tmds_channel2 = Wire(UInt(10.W))
|
||||
val tmds_channel0 = Wire(UInt(10.W))
|
||||
|
||||
val tmds_green = Module(new TMDS_encoder)
|
||||
val tmds_red = Module(new TMDS_encoder)
|
||||
val tmds_blue = Module(new TMDS_encoder)
|
||||
|
||||
tmds_red.io.video_on := sync.io.video_on
|
||||
tmds_blue.io.video_on := sync.io.video_on
|
||||
tmds_green.io.video_on := sync.io.video_on
|
||||
|
||||
tmds_blue.io.control_data := sync.io.vsync ## sync.io.hsync
|
||||
tmds_green.io.control_data := 0.U
|
||||
tmds_red.io.control_data := 0.U
|
||||
|
||||
tmds_red.io.video_data := rgb(23, 16)
|
||||
tmds_blue.io.video_data := rgb(7, 0)
|
||||
tmds_green.io.video_data := rgb(15, 8)
|
||||
|
||||
tmds_channel0 := tmds_blue.io.TMDS
|
||||
tmds_channel1 := tmds_green.io.TMDS
|
||||
tmds_channel2 := tmds_red.io.TMDS
|
||||
|
||||
val serdesBlue = Module(new Oser10Module())
|
||||
serdesBlue.io.data := tmds_channel0
|
||||
serdesBlue.io.fclk := serial_clk
|
||||
|
||||
val serdesGreen = Module(new Oser10Module())
|
||||
serdesGreen.io.data := tmds_channel1
|
||||
serdesGreen.io.fclk := serial_clk
|
||||
|
||||
val serdesRed = Module(new Oser10Module())
|
||||
serdesRed.io.data := tmds_channel2
|
||||
serdesRed.io.fclk := serial_clk
|
||||
|
||||
tmds := serdesRed.io.q ## serdesGreen.io.q ## serdesBlue.io.q
|
||||
|
||||
//serdesCLk : 25Mhz ,Why not directly use p_tick?
|
||||
//cause Duty Ratio of p_tick is 10% , while which of serdesCLk is 50%
|
||||
val serdesClk = Module(new Oser10Module())
|
||||
serdesClk.io.data := "b1111100000".U(10.W)
|
||||
serdesClk.io.fclk := serial_clk
|
||||
|
||||
tmds_clk := serdesClk.io.q
|
||||
|
||||
val buffDiffBlue = Module(new OBUFDS)
|
||||
buffDiffBlue.io.I := tmds(0)
|
||||
val buffDiffGreen = Module(new OBUFDS)
|
||||
buffDiffGreen.io.I := tmds(1)
|
||||
val buffDiffRed = Module(new OBUFDS)
|
||||
buffDiffRed.io.I := tmds(2)
|
||||
val buffDiffClk = Module(new OBUFDS)
|
||||
buffDiffClk.io.I := tmds_clk
|
||||
|
||||
io.TMDSclk_p := buffDiffClk.io.O
|
||||
io.TMDSclk_n := buffDiffClk.io.OB
|
||||
io.TMDSdata_p := buffDiffRed.io.O ## buffDiffGreen.io.O ## buffDiffBlue.io.O
|
||||
io.TMDSdata_n := buffDiffRed.io.OB ## buffDiffGreen.io.OB ## buffDiffBlue.io.OB
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
//PLL frequency multiplier using BlackBox
|
||||
class TMDS_PLLVR extends BlackBox {
|
||||
val io = IO(new Bundle {
|
||||
val clkin = Input(Clock())
|
||||
val reset = Input(Reset())
|
||||
val clkout = Output(Clock())
|
||||
val clkoutd = Output(Clock())
|
||||
val lock = Output(Bool())
|
||||
})
|
||||
}
|
||||
|
||||
/* OSER10 : serializer 10:1*/
|
||||
class OSER10 extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val Q = Output(Bool()) // OSER10 data output signal
|
||||
val D0 = Input(Bool())
|
||||
val D1 = Input(Bool())
|
||||
val D2 = Input(Bool())
|
||||
val D3 = Input(Bool())
|
||||
val D4 = Input(Bool())
|
||||
val D5 = Input(Bool())
|
||||
val D6 = Input(Bool())
|
||||
val D7 = Input(Bool())
|
||||
val D8 = Input(Bool())
|
||||
val D9 = Input(Bool()) // OSER10 data input signal
|
||||
val PCLK = Input(Clock()) // Primary clock input signal
|
||||
val FCLK = Input(Clock()) // High speed clock input signal
|
||||
val RESET = Input(Reset()) // Asynchronous reset input signal,
|
||||
//active-high.
|
||||
})
|
||||
withClockAndReset(io.FCLK, io.RESET) {
|
||||
val count = RegInit(0.U(4.W))
|
||||
val countnext = Wire(UInt(4.W))
|
||||
io.Q := MuxLookup(count, 0.U)(
|
||||
IndexedSeq(
|
||||
0.U -> io.D0.asBool,
|
||||
1.U -> io.D1.asBool,
|
||||
2.U -> io.D2.asBool,
|
||||
3.U -> io.D3.asBool,
|
||||
4.U -> io.D4.asBool,
|
||||
5.U -> io.D5.asBool,
|
||||
6.U -> io.D6.asBool,
|
||||
7.U -> io.D7.asBool,
|
||||
8.U -> io.D8.asBool,
|
||||
9.U -> io.D9.asBool
|
||||
)
|
||||
)
|
||||
countnext := Mux(
|
||||
count === 9.U, 0.U, count + 1.U
|
||||
)
|
||||
count := countnext
|
||||
}
|
||||
}
|
||||
|
||||
class Oser10Module extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val q = Output(Bool())
|
||||
val data = Input(UInt(10.W))
|
||||
val fclk = Input(Clock()) // Fast clock
|
||||
})
|
||||
|
||||
val osr10 = Module(new OSER10())
|
||||
io.q := osr10.io.Q
|
||||
osr10.io.D0 := io.data(0)
|
||||
osr10.io.D1 := io.data(1)
|
||||
osr10.io.D2 := io.data(2)
|
||||
osr10.io.D3 := io.data(3)
|
||||
osr10.io.D4 := io.data(4)
|
||||
osr10.io.D5 := io.data(5)
|
||||
osr10.io.D6 := io.data(6)
|
||||
osr10.io.D7 := io.data(7)
|
||||
osr10.io.D8 := io.data(8)
|
||||
osr10.io.D9 := io.data(9)
|
||||
osr10.io.PCLK := clock
|
||||
osr10.io.FCLK := io.fclk
|
||||
osr10.io.RESET := reset
|
||||
}
|
||||
|
||||
/* lvds output */
|
||||
class OBUFDS extends BlackBox {
|
||||
val io = IO(new Bundle {
|
||||
val O = Output(Bool())
|
||||
val OB = Output(Bool())
|
||||
val I = Input(Bool())
|
||||
})
|
||||
}
|
||||
//-----------------------------------------
|
||||
|
||||
|
||||
68
mini-yatcpu/src/main/scala/peripheral/InstructionROM.scala
Normal file
68
mini-yatcpu/src/main/scala/peripheral/InstructionROM.scala
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package peripheral
|
||||
|
||||
import chisel3._
|
||||
import chisel3.experimental.{ChiselAnnotation, annotate}
|
||||
import chisel3.util.experimental.loadMemoryFromFileInline
|
||||
import firrtl.annotations.MemorySynthInit
|
||||
import riscv.Parameters
|
||||
|
||||
import java.io.FileWriter
|
||||
import java.nio.file.{Files, Paths}
|
||||
import java.nio.{ByteBuffer, ByteOrder}
|
||||
|
||||
class InstructionROM(instructionFilename: String) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val address = Input(UInt(Parameters.AddrWidth))
|
||||
val data = Output(UInt(Parameters.InstructionWidth))
|
||||
})
|
||||
|
||||
val (instructionsInitFile, capacity) = readAsmBinary(instructionFilename)
|
||||
val mem = SyncReadMem(capacity, UInt(Parameters.InstructionWidth))
|
||||
annotate(new ChiselAnnotation {
|
||||
override def toFirrtl =
|
||||
MemorySynthInit
|
||||
})
|
||||
loadMemoryFromFileInline(mem, instructionsInitFile.toString.replaceAll("\\\\", "/"))
|
||||
io.data := mem.read(io.address, true.B)
|
||||
|
||||
def readAsmBinary(filename: String) = {
|
||||
val inputStream = if (Files.exists(Paths.get(filename))) {
|
||||
Files.newInputStream(Paths.get(filename))
|
||||
} else {
|
||||
getClass.getClassLoader.getResourceAsStream(filename)
|
||||
}
|
||||
var instructions = new Array[BigInt](0)
|
||||
val arr = new Array[Byte](4)
|
||||
while (inputStream.read(arr) == 4) {
|
||||
val instBuf = ByteBuffer.wrap(arr)
|
||||
instBuf.order(ByteOrder.LITTLE_ENDIAN)
|
||||
val inst = BigInt(instBuf.getInt() & 0xFFFFFFFFL)
|
||||
instructions = instructions :+ inst
|
||||
}
|
||||
instructions = instructions :+ BigInt(0x00000013L)
|
||||
instructions = instructions :+ BigInt(0x00000013L)
|
||||
instructions = instructions :+ BigInt(0x00000013L)
|
||||
val currentDir = System.getProperty("user.dir")
|
||||
val exeTxtPath = Paths.get(currentDir, "verilog", f"${instructionFilename}.txt")
|
||||
val writer = new FileWriter(exeTxtPath.toString)
|
||||
for (i <- instructions.indices) {
|
||||
writer.write(f"@$i%x\n${instructions(i)}%08x\n")
|
||||
}
|
||||
writer.close()
|
||||
(exeTxtPath, instructions.length)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package peripheral
|
||||
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
|
||||
// TODO(howard): implementation
|
||||
class InterruptController extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val interrupts = Vec(Parameters.SlaveDeviceCount, Bool())
|
||||
val cpu_interrupt_flag = Output(UInt(Parameters.InterruptFlagWidth))
|
||||
})
|
||||
}
|
||||
72
mini-yatcpu/src/main/scala/peripheral/Memory.scala
Normal file
72
mini-yatcpu/src/main/scala/peripheral/Memory.scala
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package peripheral
|
||||
|
||||
import bus.{AXI4LiteChannels, AXI4LiteSlave}
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
|
||||
// The purpose of this module is to help the synthesis tool recognize
|
||||
// our memory as a Block RAM template
|
||||
class BlockRAM(capacity: Int) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val read_address = Input(UInt(Parameters.AddrWidth))
|
||||
val write_address = Input(UInt(Parameters.AddrWidth))
|
||||
val write_data = Input(UInt(Parameters.DataWidth))
|
||||
val write_enable = Input(Bool())
|
||||
val write_strobe = Input(Vec(Parameters.WordSize, Bool()))
|
||||
|
||||
val debug_read_address = Input(UInt(Parameters.AddrWidth))
|
||||
|
||||
val read_data = Output(UInt(Parameters.DataWidth))
|
||||
val debug_read_data = Output(UInt(Parameters.DataWidth))
|
||||
})
|
||||
val mem = SyncReadMem(capacity, Vec(Parameters.WordSize, UInt(Parameters.ByteWidth)))
|
||||
when(io.write_enable) {
|
||||
val write_data_vec = Wire(Vec(Parameters.WordSize, UInt(Parameters.ByteWidth)))
|
||||
for (i <- 0 until Parameters.WordSize) {
|
||||
write_data_vec(i) := io.write_data((i + 1) * Parameters.ByteBits - 1, i * Parameters.ByteBits)
|
||||
}
|
||||
mem.write((io.write_address >> 2.U).asUInt, write_data_vec, io.write_strobe)
|
||||
}
|
||||
io.read_data := mem.read((io.read_address >> 2.U).asUInt, true.B).asUInt
|
||||
io.debug_read_data := mem.read((io.debug_read_address >> 2.U).asUInt, true.B).asUInt
|
||||
}
|
||||
|
||||
// This module wraps the Block RAM with an AXI4-Lite interface
|
||||
class Memory(capacity: Int) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val channels = Flipped(new AXI4LiteChannels(Parameters.AddrBits, Parameters.DataBits))
|
||||
|
||||
val debug_read_address = Input(UInt(Parameters.AddrWidth))
|
||||
val debug_read_data = Output(UInt(Parameters.DataWidth))
|
||||
})
|
||||
|
||||
val mem = Module(new BlockRAM(capacity))
|
||||
val slave = Module(new AXI4LiteSlave(Parameters.AddrBits, Parameters.DataBits))
|
||||
slave.io.channels <> io.channels
|
||||
slave.io.bundle.read_valid := true.B
|
||||
|
||||
mem.io.write_enable := slave.io.bundle.write
|
||||
mem.io.write_data := slave.io.bundle.write_data
|
||||
mem.io.write_address := slave.io.bundle.address
|
||||
mem.io.write_strobe := slave.io.bundle.write_strobe
|
||||
|
||||
mem.io.read_address := slave.io.bundle.address
|
||||
slave.io.bundle.read_data := mem.io.read_data
|
||||
|
||||
mem.io.debug_read_address := io.debug_read_address
|
||||
io.debug_read_data := mem.io.debug_read_data
|
||||
}
|
||||
55
mini-yatcpu/src/main/scala/peripheral/PixelDisplay.scala
Normal file
55
mini-yatcpu/src/main/scala/peripheral/PixelDisplay.scala
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright 2022 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package peripheral
|
||||
|
||||
import bus.{AXI4LiteChannels, AXI4LiteSlave}
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
|
||||
class PixelDisplay extends Module {
|
||||
val io = IO(new Bundle() {
|
||||
val channels = Flipped(new AXI4LiteChannels(32, Parameters.DataBits))
|
||||
|
||||
val x = Input(UInt(16.W))
|
||||
val y = Input(UInt(16.W))
|
||||
val video_on = Input(Bool())
|
||||
|
||||
val rgb = Output(UInt(24.W))
|
||||
})
|
||||
val slave = Module(new AXI4LiteSlave(32, Parameters.DataBits))
|
||||
slave.io.channels <> io.channels
|
||||
|
||||
// 320x240, RGB 565
|
||||
val mem = Module(new BlockRAM(320 * 240 / 2))
|
||||
slave.io.bundle.read_valid := true.B
|
||||
mem.io.write_enable := slave.io.bundle.write
|
||||
mem.io.write_data := slave.io.bundle.write_data
|
||||
mem.io.write_address := slave.io.bundle.address
|
||||
mem.io.write_strobe := slave.io.bundle.write_strobe
|
||||
|
||||
mem.io.read_address := slave.io.bundle.address
|
||||
slave.io.bundle.read_data := mem.io.read_data
|
||||
|
||||
|
||||
val pixel_x = io.x(15, 1).asUInt
|
||||
val pixel_y = io.y(15, 1).asUInt
|
||||
mem.io.debug_read_address := (pixel_y * 320.U + pixel_x) << 1
|
||||
|
||||
val pixel = Mux(pixel_x(0), mem.io.debug_read_data(31, 16), mem.io.debug_read_data(15, 0))
|
||||
val r = pixel(15, 11) ## 0.U(3.W)
|
||||
val g = pixel(10, 5) ## 0.U(2.W)
|
||||
val b = pixel(4, 0) ## 0.U(3.W)
|
||||
io.rgb := Mux(io.video_on, r ## g ## b, 0.U)
|
||||
}
|
||||
79
mini-yatcpu/src/main/scala/peripheral/ROMLoader.scala
Normal file
79
mini-yatcpu/src/main/scala/peripheral/ROMLoader.scala
Normal file
@@ -0,0 +1,79 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package peripheral
|
||||
|
||||
import bus.{AXI4LiteChannels, AXI4LiteMaster}
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
|
||||
class ROMLoader(capacity: Int) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val channels = new AXI4LiteChannels(Parameters.AddrBits, Parameters.InstructionBits)
|
||||
|
||||
val rom_address = Output(UInt(Parameters.AddrWidth))
|
||||
val rom_data = Input(UInt(Parameters.InstructionWidth))
|
||||
|
||||
val load_start = Input(Bool())
|
||||
val load_address = Input(UInt(Parameters.AddrWidth))
|
||||
val load_finished = Output(Bool())
|
||||
})
|
||||
val master = Module(new AXI4LiteMaster(Parameters.AddrBits, Parameters.InstructionBits))
|
||||
master.io.channels <> io.channels
|
||||
|
||||
val address = RegInit(0.U(32.W))
|
||||
val valid = RegInit(false.B)
|
||||
val loading = RegInit(false.B)
|
||||
|
||||
master.io.bundle.read := false.B
|
||||
io.load_finished := false.B
|
||||
|
||||
when(io.load_start) {
|
||||
valid := false.B
|
||||
loading := true.B
|
||||
address := 0.U
|
||||
}
|
||||
|
||||
master.io.bundle.write := false.B
|
||||
master.io.bundle.write_data := 0.U
|
||||
master.io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B))
|
||||
master.io.bundle.address := 0.U
|
||||
|
||||
when(!loading && !master.io.bundle.busy && address >= (capacity - 1).U) {
|
||||
io.load_finished := true.B
|
||||
}
|
||||
when(loading) {
|
||||
valid := true.B
|
||||
when(!master.io.bundle.busy && !master.io.bundle.write_valid) {
|
||||
when(valid) {
|
||||
master.io.bundle.write := true.B
|
||||
master.io.bundle.write_data := io.rom_data
|
||||
master.io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(true.B))
|
||||
master.io.bundle.address := (address << 2.U).asUInt + io.load_address
|
||||
}
|
||||
}
|
||||
when(master.io.bundle.write_valid) {
|
||||
when(address >= (capacity - 1).U) {
|
||||
loading := false.B
|
||||
}.otherwise {
|
||||
loading := true.B
|
||||
address := address + 1.U
|
||||
valid := false.B
|
||||
}
|
||||
}.otherwise {
|
||||
address := address
|
||||
}
|
||||
}
|
||||
io.rom_address := address
|
||||
}
|
||||
23
mini-yatcpu/src/main/scala/peripheral/SPI.scala
Normal file
23
mini-yatcpu/src/main/scala/peripheral/SPI.scala
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package peripheral
|
||||
|
||||
import chisel3._
|
||||
|
||||
class SPI extends Module {
|
||||
val io = IO(new Bundle {
|
||||
|
||||
})
|
||||
}
|
||||
65
mini-yatcpu/src/main/scala/peripheral/Timer.scala
Normal file
65
mini-yatcpu/src/main/scala/peripheral/Timer.scala
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package peripheral
|
||||
|
||||
import bus.{AXI4LiteChannels, AXI4LiteSlave}
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import riscv.Parameters
|
||||
|
||||
class Timer extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val channels = Flipped(new AXI4LiteChannels(8, Parameters.DataBits))
|
||||
val signal_interrupt = Output(Bool())
|
||||
|
||||
val debug_limit = Output(UInt(Parameters.DataWidth))
|
||||
val debug_enabled = Output(Bool())
|
||||
})
|
||||
val slave = Module(new AXI4LiteSlave(8, Parameters.DataBits))
|
||||
slave.io.channels <> io.channels
|
||||
|
||||
val count = RegInit(0.U(32.W))
|
||||
val limit = RegInit(100000000.U(32.W))
|
||||
io.debug_limit := limit
|
||||
val enabled = RegInit(true.B)
|
||||
io.debug_enabled := enabled
|
||||
|
||||
slave.io.bundle.read_data := 0.U
|
||||
slave.io.bundle.read_valid := true.B
|
||||
when(slave.io.bundle.read) {
|
||||
slave.io.bundle.read_data := MuxLookup(slave.io.bundle.address, 0.U)(
|
||||
IndexedSeq(
|
||||
0x4.U -> limit,
|
||||
0x8.U -> enabled.asUInt,
|
||||
)
|
||||
)
|
||||
}
|
||||
when(slave.io.bundle.write) {
|
||||
when(slave.io.bundle.address === 0x4.U) {
|
||||
limit := slave.io.bundle.write_data
|
||||
count := 0.U
|
||||
}.elsewhen(slave.io.bundle.address === 0x8.U) {
|
||||
enabled := slave.io.bundle.write_data =/= 0.U
|
||||
}
|
||||
}
|
||||
|
||||
io.signal_interrupt := enabled && (count >= (limit - 10.U))
|
||||
|
||||
when(count >= limit) {
|
||||
count := 0.U
|
||||
}.otherwise {
|
||||
count := count + 1.U
|
||||
}
|
||||
}
|
||||
211
mini-yatcpu/src/main/scala/peripheral/UART.scala
Normal file
211
mini-yatcpu/src/main/scala/peripheral/UART.scala
Normal file
@@ -0,0 +1,211 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package peripheral
|
||||
|
||||
import bus.{AXI4LiteChannels, AXI4LiteSlave}
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import riscv.Parameters
|
||||
|
||||
class UartIO extends DecoupledIO(UInt(8.W)) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Transmit part of the UART.
|
||||
* A minimal version without any additional buffering.
|
||||
* Use a ready/valid handshaking.
|
||||
*/
|
||||
class Tx(frequency: Int, baudRate: Int) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val txd = Output(UInt(1.W))
|
||||
val channel = Flipped(new UartIO())
|
||||
|
||||
})
|
||||
|
||||
val BIT_CNT = ((frequency + baudRate / 2) / baudRate - 1).U
|
||||
|
||||
val shiftReg = RegInit(0x7ff.U)
|
||||
val cntReg = RegInit(0.U(20.W))
|
||||
val bitsReg = RegInit(0.U(4.W))
|
||||
|
||||
io.channel.ready := (cntReg === 0.U) && (bitsReg === 0.U)
|
||||
io.txd := shiftReg(0)
|
||||
|
||||
when(cntReg === 0.U) {
|
||||
|
||||
cntReg := BIT_CNT
|
||||
when(bitsReg =/= 0.U) {
|
||||
val shift = shiftReg >> 1
|
||||
shiftReg := Cat(1.U, shift(9, 0))
|
||||
bitsReg := bitsReg - 1.U
|
||||
}.otherwise {
|
||||
when(io.channel.valid) {
|
||||
shiftReg := Cat(Cat(3.U, io.channel.bits), 0.U) // two stop bits, data, one start bit
|
||||
bitsReg := 11.U
|
||||
}.otherwise {
|
||||
shiftReg := 0x7ff.U
|
||||
}
|
||||
}
|
||||
|
||||
}.otherwise {
|
||||
cntReg := cntReg - 1.U
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive part of the UART.
|
||||
* A minimal version without any additional buffering.
|
||||
* Use a ready/valid handshaking.
|
||||
*
|
||||
* The following code is inspired by Tommy's receive code at:
|
||||
* https://github.com/tommythorn/yarvi
|
||||
*/
|
||||
class Rx(frequency: Int, baudRate: Int) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val rxd = Input(UInt(1.W))
|
||||
val channel = new UartIO()
|
||||
|
||||
})
|
||||
|
||||
val BIT_CNT = ((frequency + baudRate / 2) / baudRate - 1).U
|
||||
val START_CNT = ((3 * frequency / 2 + baudRate / 2) / baudRate - 1).U
|
||||
|
||||
// Sync in the asynchronous RX data, reset to 1 to not start reading after a reset
|
||||
val rxReg = RegNext(RegNext(io.rxd, 1.U), 1.U)
|
||||
|
||||
val shiftReg = RegInit(0.U(8.W))
|
||||
val cntReg = RegInit(0.U(20.W))
|
||||
val bitsReg = RegInit(0.U(4.W))
|
||||
val valReg = RegInit(false.B)
|
||||
|
||||
when(cntReg =/= 0.U) {
|
||||
cntReg := cntReg - 1.U
|
||||
}.elsewhen(bitsReg =/= 0.U) {
|
||||
cntReg := BIT_CNT
|
||||
shiftReg := Cat(rxReg, shiftReg >> 1)
|
||||
bitsReg := bitsReg - 1.U
|
||||
// the last shifted in
|
||||
when(bitsReg === 1.U) {
|
||||
valReg := true.B
|
||||
}
|
||||
}.elsewhen(rxReg === 0.U) { // wait 1.5 bits after falling edge of start
|
||||
cntReg := START_CNT
|
||||
bitsReg := 8.U
|
||||
}
|
||||
|
||||
when(valReg && io.channel.ready) {
|
||||
valReg := false.B
|
||||
}
|
||||
|
||||
io.channel.bits := shiftReg
|
||||
io.channel.valid := valReg
|
||||
}
|
||||
|
||||
/**
|
||||
* A single byte buffer with a ready/valid interface
|
||||
*/
|
||||
class Buffer extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val in = Flipped(new UartIO())
|
||||
val out = new UartIO()
|
||||
})
|
||||
|
||||
val empty :: full :: Nil = Enum(2)
|
||||
val stateReg = RegInit(empty)
|
||||
val dataReg = RegInit(0.U(8.W))
|
||||
|
||||
io.in.ready := stateReg === empty
|
||||
io.out.valid := stateReg === full
|
||||
|
||||
when(stateReg === empty) {
|
||||
when(io.in.valid) {
|
||||
dataReg := io.in.bits
|
||||
stateReg := full
|
||||
}
|
||||
}.otherwise { // full
|
||||
when(io.out.ready) {
|
||||
stateReg := empty
|
||||
}
|
||||
}
|
||||
io.out.bits := dataReg
|
||||
}
|
||||
|
||||
/**
|
||||
* A transmitter with a single buffer.
|
||||
*/
|
||||
class BufferedTx(frequency: Int, baudRate: Int) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val txd = Output(UInt(1.W))
|
||||
val channel = Flipped(new UartIO())
|
||||
|
||||
})
|
||||
val tx = Module(new Tx(frequency, baudRate))
|
||||
val buf = Module(new Buffer)
|
||||
|
||||
buf.io.in <> io.channel
|
||||
tx.io.channel <> buf.io.out
|
||||
io.txd <> tx.io.txd
|
||||
}
|
||||
|
||||
class Uart(frequency: Int, baudRate: Int) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val channels = Flipped(new AXI4LiteChannels(8, Parameters.DataBits))
|
||||
val rxd = Input(UInt(1.W))
|
||||
val txd = Output(UInt(1.W))
|
||||
|
||||
val signal_interrupt = Output(Bool())
|
||||
})
|
||||
val interrupt = RegInit(false.B)
|
||||
val rxData = RegInit(0.U)
|
||||
val slave = Module(new AXI4LiteSlave(8, Parameters.DataBits))
|
||||
slave.io.channels <> io.channels
|
||||
|
||||
val tx = Module(new BufferedTx(frequency, baudRate))
|
||||
val rx = Module(new Rx(frequency, baudRate))
|
||||
|
||||
slave.io.bundle.read_data := 0.U
|
||||
slave.io.bundle.read_valid := true.B
|
||||
when(slave.io.bundle.read) {
|
||||
when(slave.io.bundle.address === 0x4.U) {
|
||||
slave.io.bundle.read_data := baudRate.U
|
||||
}.elsewhen(slave.io.bundle.address === 0xC.U) {
|
||||
slave.io.bundle.read_data := rxData
|
||||
interrupt := false.B
|
||||
}
|
||||
}
|
||||
|
||||
tx.io.channel.valid := false.B
|
||||
tx.io.channel.bits := 0.U
|
||||
when(slave.io.bundle.write) {
|
||||
when(slave.io.bundle.address === 0x8.U) {
|
||||
interrupt := slave.io.bundle.write_data =/= 0.U
|
||||
}.elsewhen(slave.io.bundle.address === 0x10.U) {
|
||||
tx.io.channel.valid := true.B
|
||||
tx.io.channel.bits := slave.io.bundle.write_data
|
||||
}
|
||||
}
|
||||
|
||||
io.txd := tx.io.txd
|
||||
rx.io.rxd := io.rxd
|
||||
|
||||
io.signal_interrupt := interrupt
|
||||
rx.io.channel.ready := false.B
|
||||
when(rx.io.channel.valid) {
|
||||
rx.io.channel.ready := true.B
|
||||
rxData := rx.io.channel.bits
|
||||
interrupt := true.B
|
||||
}
|
||||
}
|
||||
117
mini-yatcpu/src/main/scala/peripheral/VGADisplay.scala
Normal file
117
mini-yatcpu/src/main/scala/peripheral/VGADisplay.scala
Normal file
@@ -0,0 +1,117 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package peripheral
|
||||
|
||||
import chisel3._
|
||||
|
||||
|
||||
class VGASync extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val hsync = Output(Bool())
|
||||
val vsync = Output(Bool())
|
||||
val video_on = Output(Bool())
|
||||
val p_tick = Output(Bool())
|
||||
val f_tick = Output(Bool())
|
||||
val x = Output(UInt(10.W))
|
||||
val y = Output(UInt(10.W))
|
||||
})
|
||||
|
||||
val DisplayHorizontal = ScreenInfo.DisplayHorizontal
|
||||
val DisplayVertical = ScreenInfo.DisplayVertical
|
||||
|
||||
val BorderLeft = 48
|
||||
val BorderRight = 16
|
||||
val BorderTop = 10
|
||||
val BorderBottom = 33
|
||||
|
||||
val RetraceHorizontal = 96
|
||||
val RetraceVertical = 2
|
||||
|
||||
val MaxHorizontal = DisplayHorizontal + BorderLeft + BorderRight + RetraceHorizontal - 1
|
||||
val MaxVertical = DisplayVertical + BorderTop + BorderBottom + RetraceVertical - 1
|
||||
|
||||
val RetraceHorizontalStart = DisplayHorizontal + BorderRight
|
||||
val RetraceHorizontalEnd = RetraceHorizontalStart + RetraceHorizontal - 1
|
||||
|
||||
val RetraceVerticalStart = DisplayVertical + BorderBottom
|
||||
val RetraceVerticalEnd = RetraceVerticalStart + RetraceVertical - 1
|
||||
|
||||
val pixel = RegInit(UInt(2.W), 0.U)
|
||||
val pixel_next = Wire(UInt(2.W))
|
||||
val pixel_tick = Wire(Bool())
|
||||
|
||||
val v_count_reg = RegInit(UInt(10.W), 0.U)
|
||||
val h_count_reg = RegInit(UInt(10.W), 0.U)
|
||||
|
||||
val v_count_next = Wire(UInt(10.W))
|
||||
val h_count_next = Wire(UInt(10.W))
|
||||
|
||||
val vsync_reg = RegInit(Bool(), false.B)
|
||||
val hsync_reg = RegInit(Bool(), false.B)
|
||||
|
||||
val vsync_next = Wire(Bool())
|
||||
val hsync_next = Wire(Bool())
|
||||
|
||||
pixel_next := pixel + 1.U
|
||||
pixel_tick := pixel === 0.U
|
||||
|
||||
h_count_next := Mux(
|
||||
pixel_tick,
|
||||
Mux(h_count_reg === MaxHorizontal.U, 0.U, h_count_reg + 1.U),
|
||||
h_count_reg
|
||||
)
|
||||
|
||||
v_count_next := Mux(
|
||||
pixel_tick && h_count_reg === MaxHorizontal.U,
|
||||
Mux(v_count_reg === MaxVertical.U, 0.U, v_count_reg + 1.U),
|
||||
v_count_reg
|
||||
)
|
||||
|
||||
hsync_next := h_count_reg >= RetraceHorizontalStart.U && h_count_reg <= RetraceHorizontalEnd.U
|
||||
vsync_next := v_count_reg >= RetraceVerticalStart.U && v_count_reg <= RetraceVerticalEnd.U
|
||||
|
||||
pixel := pixel_next
|
||||
hsync_reg := hsync_next
|
||||
vsync_reg := vsync_next
|
||||
v_count_reg := v_count_next
|
||||
h_count_reg := h_count_next
|
||||
|
||||
io.video_on := h_count_reg < DisplayHorizontal.U && v_count_reg < DisplayVertical.U
|
||||
io.hsync := hsync_reg
|
||||
io.vsync := vsync_reg
|
||||
io.x := h_count_reg
|
||||
io.y := v_count_reg
|
||||
io.p_tick := pixel_tick
|
||||
io.f_tick := io.x === 0.U && io.y === 0.U
|
||||
}
|
||||
|
||||
class VGADisplay extends Module {
|
||||
val io = IO(new Bundle() {
|
||||
val rgb = Input(UInt(24.W))
|
||||
val x = Output(UInt(16.W))
|
||||
val y = Output(UInt(16.W))
|
||||
val video_on = Output(Bool())
|
||||
|
||||
val hsync = Output(Bool())
|
||||
val vsync = Output(Bool())
|
||||
})
|
||||
|
||||
val sync = Module(new VGASync)
|
||||
io.hsync := sync.io.hsync
|
||||
io.vsync := sync.io.vsync
|
||||
io.x := sync.io.x
|
||||
io.y := sync.io.y
|
||||
io.video_on := sync.io.y
|
||||
}
|
||||
68
mini-yatcpu/src/main/scala/riscv/Parameters.scala
Normal file
68
mini-yatcpu/src/main/scala/riscv/Parameters.scala
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
object ImplementationType {
|
||||
val ThreeStage = 0
|
||||
val FiveStage = 1
|
||||
}
|
||||
|
||||
object Parameters {
|
||||
val AddrBits = 32
|
||||
val AddrWidth = AddrBits.W
|
||||
|
||||
val InstructionBits = 32
|
||||
val InstructionWidth = InstructionBits.W
|
||||
val DataBits = 32
|
||||
val DataWidth = DataBits.W
|
||||
val ByteBits = 8
|
||||
val ByteWidth = ByteBits.W
|
||||
val WordSize = Math.ceil(DataBits / ByteBits).toInt
|
||||
|
||||
val PhysicalRegisters = 32
|
||||
val PhysicalRegisterAddrBits = log2Up(PhysicalRegisters)
|
||||
val PhysicalRegisterAddrWidth = PhysicalRegisterAddrBits.W
|
||||
|
||||
val CSRRegisterAddrBits = 12
|
||||
val CSRRegisterAddrWidth = CSRRegisterAddrBits.W
|
||||
|
||||
val InterruptFlagBits = 32
|
||||
val InterruptFlagWidth = InterruptFlagBits.W
|
||||
|
||||
val HoldStateBits = 3
|
||||
val StallStateWidth = HoldStateBits.W
|
||||
|
||||
val MemorySizeInBytes = 32768
|
||||
val MemorySizeInWords = MemorySizeInBytes / 4
|
||||
|
||||
val EntryAddress = 0x1000.U(Parameters.AddrWidth)
|
||||
|
||||
val MasterDeviceCount = 1
|
||||
val SlaveDeviceCount = 8
|
||||
val SlaveDeviceCountBits = log2Up(Parameters.SlaveDeviceCount)
|
||||
// mmu
|
||||
val PageSize = 4096
|
||||
val PageOffsetBits = log2Up(Parameters.PageSize)
|
||||
val PageOffsetWidth = PageOffsetBits.W
|
||||
|
||||
val PTESize = 32
|
||||
val PTEWidth = Parameters.PTESize.W
|
||||
|
||||
|
||||
val PhysicalPageCount = Math.ceil(MemorySizeInBytes / PageSize).toInt
|
||||
}
|
||||
32
mini-yatcpu/src/main/scala/riscv/core/BusBundle.scala
Normal file
32
mini-yatcpu/src/main/scala/riscv/core/BusBundle.scala
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 2022 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core
|
||||
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
|
||||
class BusBundle extends Bundle {
|
||||
val read = Output(Bool())
|
||||
val address = Output(UInt(Parameters.AddrWidth))
|
||||
val read_data = Input(UInt(Parameters.DataWidth))
|
||||
val read_valid = Input(Bool())
|
||||
val write = Output(Bool())
|
||||
val write_data = Output(UInt(Parameters.DataWidth))
|
||||
val write_strobe = Output(Vec(Parameters.WordSize, Bool()))
|
||||
val write_valid = Input(Bool())
|
||||
val busy = Input(Bool())
|
||||
val request = Output(Bool())
|
||||
val granted = Input(Bool())
|
||||
}
|
||||
32
mini-yatcpu/src/main/scala/riscv/core/CPU.scala
Normal file
32
mini-yatcpu/src/main/scala/riscv/core/CPU.scala
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 2022 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core
|
||||
|
||||
import chisel3._
|
||||
import riscv.ImplementationType
|
||||
import riscv.core.fivestage.{CPU => FiveStageCPU}
|
||||
import riscv.core.threestage.{CPU => ThreeStageCPU}
|
||||
|
||||
class CPU(val implementation: Int = ImplementationType.FiveStage) extends Module {
|
||||
val io = IO(new CPUBundle)
|
||||
implementation match {
|
||||
case ImplementationType.ThreeStage =>
|
||||
val cpu = Module(new ThreeStageCPU)
|
||||
cpu.io <> io
|
||||
case _ =>
|
||||
val cpu = Module(new FiveStageCPU)
|
||||
cpu.io <> io
|
||||
}
|
||||
}
|
||||
32
mini-yatcpu/src/main/scala/riscv/core/CPUBundle.scala
Normal file
32
mini-yatcpu/src/main/scala/riscv/core/CPUBundle.scala
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 2022 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core
|
||||
|
||||
import bus.AXI4LiteChannels
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
|
||||
class CPUBundle extends Bundle {
|
||||
val axi4_channels = new AXI4LiteChannels(Parameters.AddrBits, Parameters.DataBits)
|
||||
val bus_address = Output(UInt(Parameters.AddrWidth))
|
||||
val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth))
|
||||
val stall_flag_bus = Input(Bool())
|
||||
val debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val debug_read_data = Output(UInt(Parameters.DataWidth))
|
||||
|
||||
val instruction_valid = Input(Bool())
|
||||
val bus_busy = Output(Bool())
|
||||
val debug = Output(Vec(6, UInt(32.W)))
|
||||
}
|
||||
69
mini-yatcpu/src/main/scala/riscv/core/fivestage/ALU.scala
Normal file
69
mini-yatcpu/src/main/scala/riscv/core/fivestage/ALU.scala
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.fivestage
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import riscv.Parameters
|
||||
|
||||
object ALUFunctions extends ChiselEnum {
|
||||
val zero, add, sub, sll, slt, xor, or, and, srl, sra, sltu = Value
|
||||
}
|
||||
|
||||
class ALU extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val func = Input(ALUFunctions())
|
||||
|
||||
val op1 = Input(UInt(Parameters.DataWidth))
|
||||
val op2 = Input(UInt(Parameters.DataWidth))
|
||||
|
||||
val result = Output(UInt(Parameters.DataWidth))
|
||||
})
|
||||
|
||||
io.result := 0.U
|
||||
switch(io.func) {
|
||||
is(ALUFunctions.add) {
|
||||
io.result := io.op1 + io.op2
|
||||
}
|
||||
is(ALUFunctions.sub) {
|
||||
io.result := io.op1 - io.op2
|
||||
}
|
||||
is(ALUFunctions.sll) {
|
||||
io.result := io.op1 << io.op2(4, 0)
|
||||
}
|
||||
is(ALUFunctions.slt) {
|
||||
io.result := io.op1.asSInt < io.op2.asSInt
|
||||
}
|
||||
is(ALUFunctions.xor) {
|
||||
io.result := io.op1 ^ io.op2
|
||||
}
|
||||
is(ALUFunctions.or) {
|
||||
io.result := io.op1 | io.op2
|
||||
}
|
||||
is(ALUFunctions.and) {
|
||||
io.result := io.op1 & io.op2
|
||||
}
|
||||
is(ALUFunctions.srl) {
|
||||
io.result := io.op1 >> io.op2(4, 0)
|
||||
}
|
||||
is(ALUFunctions.sra) {
|
||||
io.result := (io.op1.asSInt >> io.op2(4, 0)).asUInt
|
||||
}
|
||||
is(ALUFunctions.sltu) {
|
||||
io.result := io.op1 < io.op2
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.fivestage
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class ALUControl extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val opcode = Input(UInt(7.W))
|
||||
val funct3 = Input(UInt(3.W))
|
||||
val funct7 = Input(UInt(7.W))
|
||||
|
||||
val alu_funct = Output(ALUFunctions())
|
||||
})
|
||||
|
||||
io.alu_funct := ALUFunctions.zero
|
||||
|
||||
switch(io.opcode) {
|
||||
is(InstructionTypes.I) {
|
||||
io.alu_funct := MuxLookup(io.funct3, ALUFunctions.zero)(
|
||||
IndexedSeq(
|
||||
InstructionsTypeI.addi -> ALUFunctions.add,
|
||||
InstructionsTypeI.slli -> ALUFunctions.sll,
|
||||
InstructionsTypeI.slti -> ALUFunctions.slt,
|
||||
InstructionsTypeI.sltiu -> ALUFunctions.sltu,
|
||||
InstructionsTypeI.xori -> ALUFunctions.xor,
|
||||
InstructionsTypeI.ori -> ALUFunctions.or,
|
||||
InstructionsTypeI.andi -> ALUFunctions.and,
|
||||
InstructionsTypeI.sri -> Mux(io.funct7(5), ALUFunctions.sra, ALUFunctions.srl)
|
||||
),
|
||||
)
|
||||
}
|
||||
is(InstructionTypes.RM) {
|
||||
io.alu_funct := MuxLookup(io.funct3, ALUFunctions.zero)(
|
||||
IndexedSeq(
|
||||
InstructionsTypeR.add_sub -> Mux(io.funct7(5), ALUFunctions.sub, ALUFunctions.add),
|
||||
InstructionsTypeR.sll -> ALUFunctions.sll,
|
||||
InstructionsTypeR.slt -> ALUFunctions.slt,
|
||||
InstructionsTypeR.sltu -> ALUFunctions.sltu,
|
||||
InstructionsTypeR.xor -> ALUFunctions.xor,
|
||||
InstructionsTypeR.or -> ALUFunctions.or,
|
||||
InstructionsTypeR.and -> ALUFunctions.and,
|
||||
InstructionsTypeR.sr -> Mux(io.funct7(5), ALUFunctions.sra, ALUFunctions.srl)
|
||||
),
|
||||
)
|
||||
}
|
||||
is(InstructionTypes.B) {
|
||||
io.alu_funct := ALUFunctions.add
|
||||
}
|
||||
is(InstructionTypes.L) {
|
||||
io.alu_funct := ALUFunctions.add
|
||||
}
|
||||
is(InstructionTypes.S) {
|
||||
io.alu_funct := ALUFunctions.add
|
||||
}
|
||||
is(Instructions.jal) {
|
||||
io.alu_funct := ALUFunctions.add
|
||||
}
|
||||
is(Instructions.jalr) {
|
||||
io.alu_funct := ALUFunctions.add
|
||||
}
|
||||
is(Instructions.lui) {
|
||||
io.alu_funct := ALUFunctions.add
|
||||
}
|
||||
is(Instructions.auipc) {
|
||||
io.alu_funct := ALUFunctions.add
|
||||
}
|
||||
}
|
||||
}
|
||||
225
mini-yatcpu/src/main/scala/riscv/core/fivestage/CLINT.scala
Normal file
225
mini-yatcpu/src/main/scala/riscv/core/fivestage/CLINT.scala
Normal file
@@ -0,0 +1,225 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.fivestage
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import riscv.Parameters
|
||||
|
||||
object InterruptStatus {
|
||||
val None = 0x0.U(8.W)
|
||||
val Timer0 = 0x1.U(8.W)
|
||||
val Ret = 0xFF.U(8.W)
|
||||
}
|
||||
|
||||
object InterruptEntry {
|
||||
val Timer0 = 0x4.U(8.W)
|
||||
}
|
||||
|
||||
object InterruptState {
|
||||
val Idle = 0x0.U
|
||||
val SyncAssert = 0x1.U
|
||||
val AsyncAssert = 0x2.U
|
||||
val MRET = 0x3.U
|
||||
}
|
||||
|
||||
object CSRState {
|
||||
val Idle = 0x0.U
|
||||
val MSTATUS = 0x1.U
|
||||
val MEPC = 0x2.U
|
||||
val MRET = 0x3.U
|
||||
val MCAUSE = 0x4.U
|
||||
val MTVAL = 0x5.U
|
||||
}
|
||||
|
||||
// Core Local Interrupt Controller
|
||||
class CLINT extends Module {
|
||||
val io = IO(new Bundle {
|
||||
// Interrupt signals from peripherals
|
||||
val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth))
|
||||
|
||||
// Current instruction from instruction decode
|
||||
val instruction = Input(UInt(Parameters.InstructionWidth))
|
||||
val instruction_address_if = Input(UInt(Parameters.AddrWidth))
|
||||
|
||||
//exception signals from MMU etc.
|
||||
val exception_signal = Input(Bool())
|
||||
|
||||
val instruction_address_cause_exception = Input(UInt(Parameters.AddrWidth))
|
||||
val exception_cause = Input(UInt(Parameters.DataWidth))
|
||||
val exception_val = Input(UInt(Parameters.AddrWidth))
|
||||
//trick for page-fault ,synchronous with mmu
|
||||
val exception_token = Output(Bool())
|
||||
|
||||
val jump_flag = Input(Bool())
|
||||
val jump_address = Input(UInt(Parameters.AddrWidth))
|
||||
|
||||
val csr_mtvec = Input(UInt(Parameters.DataWidth))
|
||||
val csr_mepc = Input(UInt(Parameters.DataWidth))
|
||||
val csr_mstatus = Input(UInt(Parameters.DataWidth))
|
||||
|
||||
// Is global interrupt enabled (from MSTATUS)?
|
||||
val interrupt_enable = Input(Bool())
|
||||
|
||||
val ctrl_stall_flag = Output(Bool())
|
||||
|
||||
val csr_reg_write_enable = Output(Bool())
|
||||
val csr_reg_write_address = Output(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val csr_reg_write_data = Output(UInt(Parameters.DataWidth))
|
||||
|
||||
val id_interrupt_handler_address = Output(UInt(Parameters.AddrWidth))
|
||||
val id_interrupt_assert = Output(Bool())
|
||||
})
|
||||
|
||||
val interrupt_state = WireInit(0.U)
|
||||
val csr_state = RegInit(CSRState.Idle)
|
||||
val instruction_address = RegInit(UInt(Parameters.AddrWidth), 0.U)
|
||||
val cause = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||
val trap_val = RegInit(UInt(Parameters.AddrWidth), 0.U)
|
||||
val interrupt_assert = RegInit(Bool(), false.B)
|
||||
val interrupt_handler_address = RegInit(UInt(Parameters.AddrWidth), 0.U)
|
||||
val csr_reg_write_enable = RegInit(Bool(), false.B)
|
||||
val csr_reg_write_address = RegInit(UInt(Parameters.CSRRegisterAddrWidth), 0.U)
|
||||
val csr_reg_write_data = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||
val exception_token = RegInit(false.B)
|
||||
val exception_signal = RegInit(false.B)
|
||||
io.ctrl_stall_flag := (interrupt_state =/= InterruptState.Idle || csr_state =/= CSRState.Idle) && !exception_token
|
||||
io.exception_token := exception_token
|
||||
|
||||
when(exception_signal && csr_state === CSRState.MCAUSE) {
|
||||
exception_token := true.B
|
||||
}.otherwise {
|
||||
exception_token := false.B
|
||||
}
|
||||
|
||||
when(exception_token) {
|
||||
exception_signal := false.B
|
||||
}.elsewhen(exception_signal === false.B && io.exception_signal) {
|
||||
exception_signal := true.B
|
||||
}
|
||||
|
||||
// Interrupt FSM
|
||||
//exception cause SyncAssert
|
||||
when(exception_signal || io.instruction === InstructionsEnv.ecall || io.instruction === InstructionsEnv.ebreak) {
|
||||
interrupt_state := InterruptState.SyncAssert
|
||||
}.elsewhen(io.interrupt_flag =/= InterruptStatus.None && io.interrupt_enable) {
|
||||
interrupt_state := InterruptState.AsyncAssert
|
||||
}.elsewhen(io.instruction === InstructionsRet.mret) {
|
||||
interrupt_state := InterruptState.MRET
|
||||
}.otherwise {
|
||||
interrupt_state := InterruptState.Idle
|
||||
}
|
||||
|
||||
// CSR FSM
|
||||
when(csr_state === CSRState.Idle) {
|
||||
when(interrupt_state === InterruptState.SyncAssert) {
|
||||
// Synchronous Interrupt
|
||||
csr_state := CSRState.MEPC
|
||||
//exception handling first then ecall and ebreak
|
||||
instruction_address := Mux(
|
||||
exception_signal,
|
||||
io.instruction_address_cause_exception,
|
||||
Mux(
|
||||
io.jump_flag,
|
||||
io.jump_address - 4.U,
|
||||
io.instruction_address_if
|
||||
)
|
||||
)
|
||||
|
||||
cause := Mux(
|
||||
exception_signal,
|
||||
io.exception_cause,
|
||||
MuxLookup(io.instruction, 10.U)(
|
||||
IndexedSeq(
|
||||
InstructionsEnv.ecall -> 11.U,
|
||||
InstructionsEnv.ebreak -> 3.U,
|
||||
)
|
||||
)
|
||||
)
|
||||
// some trap will write mtval, otherwise set mtval to 0
|
||||
// todo: redesign CLINT to fully handle exception, like trap priority handling
|
||||
// hint: currently we have only page_fault to write mtval
|
||||
trap_val := Mux(
|
||||
exception_signal,
|
||||
io.exception_val,
|
||||
0.U
|
||||
)
|
||||
}.elsewhen(interrupt_state === InterruptState.AsyncAssert) { //
|
||||
// Asynchronous Interrupt
|
||||
cause := 0x8000000BL.U // Interrupt from peripherals : Uart
|
||||
when(io.interrupt_flag(0)) {
|
||||
cause := 0x80000007L.U // Interrupt from timer
|
||||
}
|
||||
trap_val := 0.U
|
||||
csr_state := CSRState.MEPC
|
||||
instruction_address := Mux(
|
||||
io.jump_flag,
|
||||
io.jump_address,
|
||||
io.instruction_address_if,
|
||||
)
|
||||
}.elsewhen(interrupt_state === InterruptState.MRET) {
|
||||
// Interrupt Return
|
||||
csr_state := CSRState.MRET
|
||||
}
|
||||
}.elsewhen(csr_state === CSRState.MEPC) {
|
||||
csr_state := CSRState.MSTATUS
|
||||
}.elsewhen(csr_state === CSRState.MSTATUS) {
|
||||
csr_state := CSRState.MTVAL
|
||||
}.elsewhen(csr_state === CSRState.MTVAL) {
|
||||
csr_state := CSRState.MCAUSE
|
||||
}.elsewhen(csr_state === CSRState.MCAUSE) {
|
||||
csr_state := CSRState.Idle
|
||||
}.elsewhen(csr_state === CSRState.MRET) {
|
||||
csr_state := CSRState.Idle
|
||||
}.otherwise {
|
||||
csr_state := CSRState.Idle
|
||||
}
|
||||
|
||||
csr_reg_write_enable := csr_state =/= CSRState.Idle
|
||||
csr_reg_write_address := Cat(Fill(20, 0.U(1.W)), MuxLookup(csr_state, 0.U(Parameters.CSRRegisterAddrWidth))(
|
||||
IndexedSeq(
|
||||
CSRState.MEPC -> CSRRegister.MEPC,
|
||||
CSRState.MCAUSE -> CSRRegister.MCAUSE,
|
||||
CSRState.MSTATUS -> CSRRegister.MSTATUS,
|
||||
CSRState.MRET -> CSRRegister.MSTATUS,
|
||||
CSRState.MTVAL -> CSRRegister.MTVAL
|
||||
)
|
||||
))
|
||||
|
||||
csr_reg_write_data := MuxLookup(csr_state, 0.U(Parameters.DataWidth))(
|
||||
IndexedSeq(
|
||||
CSRState.MEPC -> instruction_address,
|
||||
CSRState.MCAUSE -> cause,
|
||||
CSRState.MSTATUS -> Cat(io.csr_mstatus(31, 4), 0.U(1.W), io.csr_mstatus(2, 0)),
|
||||
CSRState.MRET -> Cat(io.csr_mstatus(31, 4), io.csr_mstatus(7), io.csr_mstatus(2, 0)),
|
||||
CSRState.MTVAL -> trap_val,
|
||||
)
|
||||
)
|
||||
|
||||
io.csr_reg_write_enable := csr_reg_write_enable
|
||||
io.csr_reg_write_address := csr_reg_write_address
|
||||
io.csr_reg_write_data := csr_reg_write_data
|
||||
|
||||
interrupt_assert := csr_state === CSRState.MCAUSE || csr_state === CSRState.MRET
|
||||
interrupt_handler_address := MuxLookup(csr_state, 0.U(Parameters.AddrWidth))(
|
||||
IndexedSeq(
|
||||
CSRState.MCAUSE -> io.csr_mtvec,
|
||||
CSRState.MRET -> io.csr_mepc,
|
||||
)
|
||||
)
|
||||
|
||||
io.id_interrupt_assert := interrupt_assert
|
||||
io.id_interrupt_handler_address := interrupt_handler_address
|
||||
}
|
||||
385
mini-yatcpu/src/main/scala/riscv/core/fivestage/CPU.scala
Normal file
385
mini-yatcpu/src/main/scala/riscv/core/fivestage/CPU.scala
Normal file
@@ -0,0 +1,385 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.fivestage
|
||||
|
||||
import bus.AXI4LiteMaster
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
import riscv.core.CPUBundle
|
||||
|
||||
object BUSGranted extends ChiselEnum {
|
||||
val idle, if_granted, mem_granted, mmu_mem_granted, mmu_if_granted = Value
|
||||
}
|
||||
|
||||
object MEMAccessState extends ChiselEnum {
|
||||
val idle, if_address_translate, mem_address_translate, mem_access, if_access = Value
|
||||
}
|
||||
|
||||
class CPU extends Module {
|
||||
val io = IO(new CPUBundle)
|
||||
|
||||
val ctrl = Module(new Control)
|
||||
val regs = Module(new RegisterFile)
|
||||
val inst_fetch = Module(new InstructionFetch)
|
||||
val if2id = Module(new IF2ID)
|
||||
val id = Module(new InstructionDecode)
|
||||
val id2ex = Module(new ID2EX)
|
||||
val ex = Module(new Execute)
|
||||
val ex2mem = Module(new EX2MEM)
|
||||
val mem = Module(new MemoryAccess)
|
||||
val mem2wb = Module(new MEM2WB)
|
||||
val wb = Module(new WriteBack)
|
||||
val forwarding = Module(new Forwarding)
|
||||
val clint = Module(new CLINT)
|
||||
val csr_regs = Module(new CSR)
|
||||
val axi4_master = Module(new AXI4LiteMaster(Parameters.AddrBits, Parameters.DataBits))
|
||||
val mmu = Module(new MMU)
|
||||
axi4_master.io.channels <> io.axi4_channels
|
||||
io.debug(0) := ex.io.reg1_data
|
||||
io.debug(1) := ex.io.reg2_data
|
||||
io.debug(2) := ex.io.instruction_address
|
||||
io.debug(3) := ex.io.instruction
|
||||
io.debug(4) := inst_fetch.io.jump_address_id
|
||||
io.debug(5) := inst_fetch.io.jump_flag_id
|
||||
io.bus_busy := axi4_master.io.bundle.busy
|
||||
|
||||
val bus_granted = RegInit(BUSGranted.idle)
|
||||
val mem_access_state = RegInit(MEMAccessState.idle)
|
||||
val virtual_address = RegInit(UInt(Parameters.AddrWidth), 0.U)
|
||||
val physical_address = RegInit(UInt(Parameters.AddrWidth), 0.U)
|
||||
val mmu_restart = RegInit(false.B)
|
||||
val pending = RegInit(false.B) //play the same role as pending_jump in Inst_fetch
|
||||
|
||||
//bus arbitration
|
||||
when(mem_access_state === MEMAccessState.idle) {
|
||||
bus_granted := BUSGranted.idle
|
||||
when(!axi4_master.io.bundle.busy && !axi4_master.io.bundle.read_valid) {
|
||||
when(csr_regs.io.mmu_enable) {
|
||||
when(mem.io.bus.request) {
|
||||
mem_access_state := MEMAccessState.mem_address_translate
|
||||
bus_granted := BUSGranted.mmu_mem_granted
|
||||
virtual_address := ex2mem.io.output_alu_result
|
||||
}.elsewhen(inst_fetch.io.bus.request && io.instruction_valid && inst_fetch.io.pc_valid) {
|
||||
mem_access_state := MEMAccessState.if_address_translate
|
||||
bus_granted := BUSGranted.mmu_if_granted
|
||||
virtual_address := inst_fetch.io.id_instruction_address
|
||||
}
|
||||
}.otherwise {
|
||||
when(mem.io.bus.request) {
|
||||
mem_access_state := MEMAccessState.mem_access
|
||||
physical_address := ex2mem.io.output_alu_result
|
||||
bus_granted := BUSGranted.mem_granted
|
||||
}.elsewhen(inst_fetch.io.bus.request && io.instruction_valid && inst_fetch.io.pc_valid) {
|
||||
mem_access_state := MEMAccessState.if_access
|
||||
bus_granted := BUSGranted.if_granted
|
||||
physical_address := inst_fetch.io.id_instruction_address
|
||||
}
|
||||
}
|
||||
}
|
||||
}.elsewhen(mem_access_state === MEMAccessState.mem_address_translate) {
|
||||
when(clint.io.exception_token) {
|
||||
mem_access_state := MEMAccessState.if_address_translate
|
||||
bus_granted := BUSGranted.mmu_if_granted
|
||||
virtual_address := id.io.if_jump_address
|
||||
}.elsewhen(mmu.io.pa_valid) {
|
||||
mem_access_state := MEMAccessState.mem_access
|
||||
bus_granted := BUSGranted.mem_granted
|
||||
physical_address := mmu.io.pa
|
||||
}
|
||||
}.elsewhen(mem_access_state === MEMAccessState.if_address_translate) {
|
||||
//"Interrupt" the IF address translation, turn to mem address translation
|
||||
when(mem.io.bus.request) {
|
||||
mmu_restart := true.B
|
||||
when(mmu.io.restart_done) {
|
||||
mmu_restart := false.B
|
||||
mem_access_state := MEMAccessState.mem_address_translate
|
||||
bus_granted := BUSGranted.mmu_mem_granted
|
||||
virtual_address := ex2mem.io.output_alu_result
|
||||
}
|
||||
}.otherwise {
|
||||
when(pending) {
|
||||
when(mmu.io.restart_done) {
|
||||
mmu_restart := false.B
|
||||
pending := false.B
|
||||
mem_access_state := MEMAccessState.if_address_translate
|
||||
bus_granted := BUSGranted.mmu_if_granted
|
||||
virtual_address := inst_fetch.io.id_instruction_address
|
||||
}
|
||||
}.otherwise {
|
||||
when(!id.io.if_jump_flag && mmu.io.pa_valid) {
|
||||
mem_access_state := MEMAccessState.if_access
|
||||
bus_granted := BUSGranted.if_granted
|
||||
physical_address := mmu.io.pa
|
||||
}
|
||||
}
|
||||
|
||||
when(id.io.if_jump_flag) {
|
||||
mmu_restart := true.B
|
||||
pending := true.B
|
||||
}
|
||||
}
|
||||
}.elsewhen(mem_access_state === MEMAccessState.mem_access) {
|
||||
when(mem.io.bus.read_valid || mem.io.bus.write_valid) {
|
||||
mem_access_state := MEMAccessState.idle
|
||||
bus_granted := BUSGranted.idle
|
||||
}
|
||||
}.elsewhen(mem_access_state === MEMAccessState.if_access) {
|
||||
when(inst_fetch.io.bus.read_valid) {
|
||||
bus_granted := BUSGranted.idle
|
||||
mem_access_state := MEMAccessState.idle
|
||||
}
|
||||
}
|
||||
|
||||
when(bus_granted === BUSGranted.mmu_if_granted || bus_granted === BUSGranted.mmu_mem_granted) {
|
||||
io.bus_address := mmu.io.bus.address
|
||||
axi4_master.io.bundle.read := mmu.io.bus.read
|
||||
axi4_master.io.bundle.address := mmu.io.bus.address
|
||||
axi4_master.io.bundle.write := mmu.io.bus.write
|
||||
axi4_master.io.bundle.write_data := mmu.io.bus.write_data
|
||||
axi4_master.io.bundle.write_strobe := mmu.io.bus.write_strobe
|
||||
}.elsewhen(bus_granted === BUSGranted.mem_granted) {
|
||||
io.bus_address := mem.io.bus.address
|
||||
axi4_master.io.bundle.read := mem.io.bus.read
|
||||
axi4_master.io.bundle.address := mem.io.bus.address
|
||||
axi4_master.io.bundle.write := mem.io.bus.write
|
||||
axi4_master.io.bundle.write_data := mem.io.bus.write_data
|
||||
axi4_master.io.bundle.write_strobe := mem.io.bus.write_strobe
|
||||
}.otherwise {
|
||||
io.bus_address := inst_fetch.io.bus.address
|
||||
axi4_master.io.bundle.read := inst_fetch.io.bus.read
|
||||
axi4_master.io.bundle.address := inst_fetch.io.bus.address
|
||||
axi4_master.io.bundle.write := inst_fetch.io.bus.write
|
||||
axi4_master.io.bundle.write_data := inst_fetch.io.bus.write_data
|
||||
axi4_master.io.bundle.write_strobe := inst_fetch.io.bus.write_strobe
|
||||
}
|
||||
|
||||
inst_fetch.io.bus.read_valid := Mux(
|
||||
bus_granted === BUSGranted.if_granted && io.instruction_valid,
|
||||
axi4_master.io.bundle.read_valid,
|
||||
false.B
|
||||
)
|
||||
inst_fetch.io.bus.read_data := Mux(
|
||||
bus_granted === BUSGranted.if_granted && io.instruction_valid,
|
||||
axi4_master.io.bundle.read_data,
|
||||
0.U
|
||||
)
|
||||
inst_fetch.io.bus.write_valid := false.B
|
||||
inst_fetch.io.bus.busy := Mux(
|
||||
bus_granted === BUSGranted.if_granted && io.instruction_valid,
|
||||
axi4_master.io.bundle.busy,
|
||||
false.B
|
||||
)
|
||||
mem.io.bus.read_valid := Mux(
|
||||
bus_granted === BUSGranted.mem_granted,
|
||||
axi4_master.io.bundle.read_valid,
|
||||
false.B
|
||||
)
|
||||
mem.io.bus.read_data := Mux(
|
||||
bus_granted === BUSGranted.mem_granted,
|
||||
axi4_master.io.bundle.read_data,
|
||||
0.U
|
||||
)
|
||||
mem.io.bus.write_valid := Mux(
|
||||
bus_granted === BUSGranted.mem_granted,
|
||||
axi4_master.io.bundle.write_valid,
|
||||
false.B
|
||||
)
|
||||
mem.io.bus.busy := Mux(
|
||||
bus_granted === BUSGranted.mem_granted,
|
||||
axi4_master.io.bundle.busy,
|
||||
false.B
|
||||
)
|
||||
mmu.io.bus.read_valid := Mux(
|
||||
bus_granted === BUSGranted.mmu_if_granted || bus_granted === BUSGranted.mmu_mem_granted,
|
||||
axi4_master.io.bundle.read_valid,
|
||||
false.B
|
||||
)
|
||||
mmu.io.bus.read_data := Mux(
|
||||
bus_granted === BUSGranted.mmu_if_granted || bus_granted === BUSGranted.mmu_mem_granted,
|
||||
axi4_master.io.bundle.read_data,
|
||||
0.U
|
||||
)
|
||||
mmu.io.bus.write_valid := Mux(
|
||||
bus_granted === BUSGranted.mmu_if_granted || bus_granted === BUSGranted.mmu_mem_granted,
|
||||
axi4_master.io.bundle.write_valid,
|
||||
false.B
|
||||
)
|
||||
mmu.io.bus.busy := Mux(
|
||||
bus_granted === BUSGranted.mmu_if_granted || bus_granted === BUSGranted.mmu_mem_granted,
|
||||
axi4_master.io.bundle.busy,
|
||||
false.B
|
||||
)
|
||||
|
||||
mmu.io.instructions := ex2mem.io.output_instruction
|
||||
mmu.io.instructions_address := ex2mem.io.output_instruction_address
|
||||
mmu.io.virtual_address := virtual_address
|
||||
mmu.io.bus.granted := bus_granted === BUSGranted.mmu_mem_granted || bus_granted === BUSGranted.mmu_if_granted
|
||||
mmu.io.page_fault_responed := false.B
|
||||
mmu.io.ppn_from_satp := csr_regs.io.mmu_csr_satp(21, 0)
|
||||
mmu.io.page_fault_responed := clint.io.exception_token
|
||||
mmu.io.mmu_occupied_by_mem := bus_granted === BUSGranted.mmu_mem_granted
|
||||
mmu.io.restart := mmu_restart
|
||||
|
||||
inst_fetch.io.bus.granted := bus_granted === BUSGranted.if_granted
|
||||
inst_fetch.io.physical_address := physical_address
|
||||
|
||||
mem.io.bus.granted := bus_granted === BUSGranted.mem_granted
|
||||
mem.io.physical_address := physical_address
|
||||
|
||||
ctrl.io.jump_flag := id.io.if_jump_flag
|
||||
ctrl.io.jump_instruction_id := id.io.ctrl_jump_instruction
|
||||
ctrl.io.stall_flag_if := inst_fetch.io.ctrl_stall_flag
|
||||
ctrl.io.stall_flag_mem := mem.io.ctrl_stall_flag
|
||||
ctrl.io.stall_flag_clint := clint.io.ctrl_stall_flag
|
||||
ctrl.io.stall_flag_bus := io.stall_flag_bus
|
||||
ctrl.io.rs1_id := id.io.regs_reg1_read_address
|
||||
ctrl.io.rs2_id := id.io.regs_reg2_read_address
|
||||
ctrl.io.memory_read_enable_ex := id2ex.io.output_memory_read_enable
|
||||
ctrl.io.rd_ex := id2ex.io.output_regs_write_address
|
||||
ctrl.io.memory_read_enable_mem := ex2mem.io.output_memory_read_enable
|
||||
ctrl.io.rd_mem := ex2mem.io.output_regs_write_address
|
||||
ctrl.io.csr_start_paging := csr_regs.io.start_paging
|
||||
|
||||
regs.io.write_enable := mem2wb.io.output_regs_write_enable
|
||||
regs.io.write_address := mem2wb.io.output_regs_write_address
|
||||
regs.io.write_data := wb.io.regs_write_data
|
||||
regs.io.read_address1 := id.io.regs_reg1_read_address
|
||||
regs.io.read_address2 := id.io.regs_reg2_read_address
|
||||
|
||||
regs.io.debug_read_address := io.debug_read_address
|
||||
io.debug_read_data := regs.io.debug_read_data
|
||||
|
||||
inst_fetch.io.stall_flag_ctrl := ctrl.io.pc_stall
|
||||
inst_fetch.io.jump_flag_id := id.io.if_jump_flag
|
||||
inst_fetch.io.jump_address_id := id.io.if_jump_address
|
||||
|
||||
if2id.io.stall_flag := ctrl.io.if_stall
|
||||
if2id.io.flush_enable := ctrl.io.if_flush
|
||||
if2id.io.instruction := inst_fetch.io.id_instruction
|
||||
if2id.io.instruction_address := inst_fetch.io.id_instruction_address
|
||||
if2id.io.interrupt_flag := io.interrupt_flag
|
||||
|
||||
id.io.instruction := if2id.io.output_instruction
|
||||
id.io.instruction_address := if2id.io.output_instruction_address
|
||||
id.io.reg1_data := regs.io.read_data1
|
||||
id.io.reg2_data := regs.io.read_data2
|
||||
id.io.forward_from_mem := mem.io.forward_data
|
||||
id.io.forward_from_wb := wb.io.regs_write_data
|
||||
id.io.reg1_forward := forwarding.io.reg1_forward_id
|
||||
id.io.reg2_forward := forwarding.io.reg2_forward_id
|
||||
id.io.interrupt_assert := clint.io.id_interrupt_assert
|
||||
id.io.interrupt_handler_address := clint.io.id_interrupt_handler_address
|
||||
|
||||
id2ex.io.stall_flag := ctrl.io.id_stall
|
||||
id2ex.io.flush_enable := ctrl.io.id_flush
|
||||
id2ex.io.instruction := if2id.io.output_instruction
|
||||
id2ex.io.instruction_address := if2id.io.output_instruction_address
|
||||
id2ex.io.regs_write_enable := id.io.ex_reg_write_enable
|
||||
id2ex.io.regs_write_address := id.io.ex_reg_write_address
|
||||
id2ex.io.regs_write_source := id.io.ex_reg_write_source
|
||||
id2ex.io.reg1_data := regs.io.read_data1
|
||||
id2ex.io.reg2_data := regs.io.read_data2
|
||||
id2ex.io.immediate := id.io.ex_immediate
|
||||
id2ex.io.aluop1_source := id.io.ex_aluop1_source
|
||||
id2ex.io.aluop2_source := id.io.ex_aluop2_source
|
||||
id2ex.io.csr_write_enable := id.io.ex_csr_write_enable
|
||||
id2ex.io.csr_address := id.io.ex_csr_address
|
||||
id2ex.io.memory_read_enable := id.io.ex_memory_read_enable
|
||||
id2ex.io.memory_write_enable := id.io.ex_memory_write_enable
|
||||
id2ex.io.csr_read_data := csr_regs.io.id_reg_data
|
||||
|
||||
ex.io.instruction := id2ex.io.output_instruction
|
||||
ex.io.instruction_address := id2ex.io.output_instruction_address
|
||||
ex.io.reg1_data := id2ex.io.output_reg1_data
|
||||
ex.io.reg2_data := id2ex.io.output_reg2_data
|
||||
ex.io.immediate := id2ex.io.output_immediate
|
||||
ex.io.aluop1_source := id2ex.io.output_aluop1_source
|
||||
ex.io.aluop2_source := id2ex.io.output_aluop2_source
|
||||
ex.io.csr_read_data := id2ex.io.output_csr_read_data
|
||||
ex.io.forward_from_mem := mem.io.forward_data
|
||||
ex.io.forward_from_wb := wb.io.regs_write_data
|
||||
ex.io.reg1_forward := forwarding.io.reg1_forward_ex
|
||||
ex.io.reg2_forward := forwarding.io.reg2_forward_ex
|
||||
|
||||
ex2mem.io.stall_flag := ctrl.io.ex_stall
|
||||
ex2mem.io.flush_enable := false.B
|
||||
ex2mem.io.regs_write_enable := id2ex.io.output_regs_write_enable
|
||||
ex2mem.io.regs_write_source := id2ex.io.output_regs_write_source
|
||||
ex2mem.io.regs_write_address := id2ex.io.output_regs_write_address
|
||||
ex2mem.io.instruction_address := id2ex.io.output_instruction_address
|
||||
ex2mem.io.instruction := id2ex.io.output_instruction
|
||||
ex2mem.io.reg1_data := id2ex.io.output_reg1_data
|
||||
ex2mem.io.reg2_data := id2ex.io.output_reg2_data
|
||||
ex2mem.io.memory_read_enable := id2ex.io.output_memory_read_enable
|
||||
ex2mem.io.memory_write_enable := id2ex.io.output_memory_write_enable
|
||||
ex2mem.io.alu_result := ex.io.mem_alu_result
|
||||
ex2mem.io.csr_read_data := id2ex.io.output_csr_read_data
|
||||
|
||||
mem.io.alu_result := ex2mem.io.output_alu_result
|
||||
mem.io.reg2_data := ex2mem.io.output_reg2_data
|
||||
mem.io.memory_read_enable := ex2mem.io.output_memory_read_enable
|
||||
mem.io.memory_write_enable := ex2mem.io.output_memory_write_enable
|
||||
mem.io.funct3 := ex2mem.io.output_instruction(14, 12)
|
||||
mem.io.regs_write_source := ex2mem.io.output_regs_write_source
|
||||
mem.io.csr_read_data := ex2mem.io.output_csr_read_data
|
||||
mem.io.clint_exception_token := clint.io.exception_token
|
||||
|
||||
mem2wb.io.instruction_address := ex2mem.io.output_instruction_address
|
||||
mem2wb.io.alu_result := ex2mem.io.output_alu_result
|
||||
mem2wb.io.regs_write_enable := ex2mem.io.output_regs_write_enable
|
||||
mem2wb.io.regs_write_source := ex2mem.io.output_regs_write_source
|
||||
mem2wb.io.regs_write_address := ex2mem.io.output_regs_write_address
|
||||
mem2wb.io.memory_read_data := mem.io.wb_memory_read_data
|
||||
mem2wb.io.csr_read_data := ex2mem.io.output_csr_read_data
|
||||
|
||||
wb.io.instruction_address := mem2wb.io.output_instruction_address
|
||||
wb.io.alu_result := mem2wb.io.output_alu_result
|
||||
wb.io.memory_read_data := mem2wb.io.output_memory_read_data
|
||||
wb.io.regs_write_source := mem2wb.io.output_regs_write_source
|
||||
wb.io.csr_read_data := mem2wb.io.output_csr_read_data
|
||||
|
||||
forwarding.io.rs1_id := id.io.regs_reg1_read_address
|
||||
forwarding.io.rs2_id := id.io.regs_reg2_read_address
|
||||
forwarding.io.rs1_ex := id2ex.io.output_instruction(19, 15)
|
||||
forwarding.io.rs2_ex := id2ex.io.output_instruction(24, 20)
|
||||
forwarding.io.rd_mem := ex2mem.io.output_regs_write_address
|
||||
forwarding.io.reg_write_enable_mem := ex2mem.io.output_regs_write_enable
|
||||
forwarding.io.rd_wb := mem2wb.io.output_regs_write_address
|
||||
forwarding.io.reg_write_enable_wb := mem2wb.io.output_regs_write_enable
|
||||
|
||||
clint.io.instruction := if2id.io.output_instruction
|
||||
clint.io.instruction_address_if := inst_fetch.io.id_instruction_address
|
||||
clint.io.jump_flag := id.io.if_jump_flag
|
||||
clint.io.jump_address := id.io.clint_jump_address
|
||||
clint.io.csr_mepc := csr_regs.io.clint_csr_mepc
|
||||
clint.io.csr_mtvec := csr_regs.io.clint_csr_mtvec
|
||||
clint.io.csr_mstatus := csr_regs.io.clint_csr_mstatus
|
||||
clint.io.interrupt_enable := csr_regs.io.interrupt_enable
|
||||
clint.io.interrupt_flag := if2id.io.output_interrupt_flag
|
||||
//todo: change it for handling more exceptions
|
||||
clint.io.exception_signal := mmu.io.page_fault_signals
|
||||
clint.io.instruction_address_cause_exception := mmu.io.epc
|
||||
clint.io.exception_val := mmu.io.va_cause_page_fault
|
||||
clint.io.exception_cause := mmu.io.ecause
|
||||
|
||||
csr_regs.io.reg_write_enable_ex := id2ex.io.output_csr_write_enable
|
||||
csr_regs.io.reg_write_address_ex := id2ex.io.output_csr_address
|
||||
csr_regs.io.reg_write_data_ex := ex.io.csr_write_data
|
||||
csr_regs.io.reg_read_address_id := id.io.ex_csr_address
|
||||
csr_regs.io.reg_write_enable_clint := clint.io.csr_reg_write_enable
|
||||
csr_regs.io.reg_write_address_clint := clint.io.csr_reg_write_address
|
||||
csr_regs.io.reg_write_data_clint := clint.io.csr_reg_write_data
|
||||
csr_regs.io.reg_read_address_clint := 0.U
|
||||
}
|
||||
141
mini-yatcpu/src/main/scala/riscv/core/fivestage/CSR.scala
Normal file
141
mini-yatcpu/src/main/scala/riscv/core/fivestage/CSR.scala
Normal file
@@ -0,0 +1,141 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.fivestage
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import riscv.Parameters
|
||||
|
||||
|
||||
object CSRRegister {
|
||||
// Refer to Spec. Vol.II Page 8-10
|
||||
val CycleL = 0xc00.U(Parameters.CSRRegisterAddrWidth)
|
||||
val CycleH = 0xc80.U(Parameters.CSRRegisterAddrWidth)
|
||||
val MTVEC = 0x305.U(Parameters.CSRRegisterAddrWidth)
|
||||
val MCAUSE = 0x342.U(Parameters.CSRRegisterAddrWidth)
|
||||
val MEPC = 0x341.U(Parameters.CSRRegisterAddrWidth)
|
||||
val MIE = 0x304.U(Parameters.CSRRegisterAddrWidth)
|
||||
val MSTATUS = 0x300.U(Parameters.CSRRegisterAddrWidth)
|
||||
val MSCRATCH = 0x340.U(Parameters.CSRRegisterAddrWidth)
|
||||
val MTVAL = 0x343.U(Parameters.CSRRegisterAddrWidth)
|
||||
val SATP = 0x180.U(Parameters.CSRRegisterAddrWidth)
|
||||
}
|
||||
|
||||
class CSR extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val reg_write_enable_ex = Input(Bool())
|
||||
val reg_read_address_id = Input(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val reg_write_address_ex = Input(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val reg_write_data_ex = Input(UInt(Parameters.DataWidth))
|
||||
|
||||
val reg_write_enable_clint = Input(Bool())
|
||||
val reg_read_address_clint = Input(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val reg_write_address_clint = Input(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val reg_write_data_clint = Input(UInt(Parameters.DataWidth))
|
||||
|
||||
val interrupt_enable = Output(Bool())
|
||||
val mmu_enable = Output(Bool())
|
||||
val id_reg_data = Output(UInt(Parameters.DataWidth))
|
||||
|
||||
val start_paging = Output(Bool())
|
||||
|
||||
val clint_reg_data = Output(UInt(Parameters.DataWidth))
|
||||
val clint_csr_mtvec = Output(UInt(Parameters.DataWidth))
|
||||
val clint_csr_mepc = Output(UInt(Parameters.DataWidth))
|
||||
val clint_csr_mstatus = Output(UInt(Parameters.DataWidth))
|
||||
val mmu_csr_satp = Output(UInt(Parameters.DataWidth))
|
||||
})
|
||||
|
||||
|
||||
val cycles = RegInit(UInt(64.W), 0.U)
|
||||
val mtvec = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||
val mcause = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||
val mepc = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||
val mie = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||
val mstatus = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||
val mscratch = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||
val mtval = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||
val satp = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||
|
||||
cycles := cycles + 1.U
|
||||
io.clint_csr_mtvec := mtvec
|
||||
io.clint_csr_mepc := mepc
|
||||
io.clint_csr_mstatus := mstatus
|
||||
io.interrupt_enable := mstatus(3) === 1.U
|
||||
io.mmu_csr_satp := satp
|
||||
io.mmu_enable := satp(31) === 1.U
|
||||
io.start_paging := false.B
|
||||
|
||||
val reg_write_address = Wire(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val reg_write_data = Wire(UInt(Parameters.DataWidth))
|
||||
reg_write_address := 0.U
|
||||
reg_write_data := 0.U
|
||||
|
||||
val reg_read_address = Wire(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val reg_read_data = Wire(UInt(Parameters.DataWidth))
|
||||
reg_read_address := 0.U
|
||||
reg_read_data := 0.U
|
||||
|
||||
when(io.reg_write_enable_ex) {
|
||||
reg_write_address := io.reg_write_address_ex(11, 0)
|
||||
reg_write_data := io.reg_write_data_ex
|
||||
}.elsewhen(io.reg_write_enable_clint) {
|
||||
reg_write_address := io.reg_write_address_clint(11, 0)
|
||||
reg_write_data := io.reg_write_data_clint
|
||||
}
|
||||
|
||||
when(reg_write_address === CSRRegister.MTVEC) {
|
||||
mtvec := reg_write_data
|
||||
}.elsewhen(reg_write_address === CSRRegister.MCAUSE) {
|
||||
mcause := reg_write_data
|
||||
}.elsewhen(reg_write_address === CSRRegister.MEPC) {
|
||||
mepc := reg_write_data
|
||||
}.elsewhen(reg_write_address === CSRRegister.MIE) {
|
||||
mie := reg_write_data
|
||||
}.elsewhen(reg_write_address === CSRRegister.MSTATUS) {
|
||||
mstatus := reg_write_data
|
||||
}.elsewhen(reg_write_address === CSRRegister.MSCRATCH) {
|
||||
mscratch := reg_write_data
|
||||
}.elsewhen(reg_write_address === CSRRegister.MTVAL) {
|
||||
mtval := reg_write_data
|
||||
}.elsewhen(reg_write_address === CSRRegister.SATP) {
|
||||
satp := reg_write_data
|
||||
when(reg_write_data(31) === 1.U && satp(31) === 0.U) {
|
||||
io.start_paging := true.B
|
||||
}
|
||||
}
|
||||
|
||||
val regLUT =
|
||||
IndexedSeq(
|
||||
CSRRegister.CycleL -> cycles(31, 0),
|
||||
CSRRegister.CycleH -> cycles(63, 32),
|
||||
CSRRegister.MTVEC -> mtvec,
|
||||
CSRRegister.MCAUSE -> mcause,
|
||||
CSRRegister.MEPC -> mepc,
|
||||
CSRRegister.MIE -> mie,
|
||||
CSRRegister.MSTATUS -> mstatus,
|
||||
CSRRegister.MSCRATCH -> mscratch,
|
||||
CSRRegister.MTVAL -> mtval,
|
||||
CSRRegister.SATP -> satp,
|
||||
)
|
||||
|
||||
io.id_reg_data := MuxLookup(io.reg_read_address_id, 0.U)(
|
||||
regLUT
|
||||
)
|
||||
|
||||
io.clint_reg_data := MuxLookup(io.reg_read_address_clint, 0.U)(
|
||||
regLUT
|
||||
)
|
||||
}
|
||||
23
mini-yatcpu/src/main/scala/riscv/core/fivestage/Cache.scala
Normal file
23
mini-yatcpu/src/main/scala/riscv/core/fivestage/Cache.scala
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.fivestage
|
||||
|
||||
import chisel3._
|
||||
|
||||
class Cache(cacheLineBytes: Int, associativity: Int, cacheLines: Int) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.fivestage
|
||||
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
|
||||
class Control extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val jump_flag = Input(Bool())
|
||||
val jump_instruction_id = Input(Bool())
|
||||
val stall_flag_if = Input(Bool())
|
||||
val stall_flag_mem = Input(Bool())
|
||||
val stall_flag_clint = Input(Bool())
|
||||
val stall_flag_bus = Input(Bool())
|
||||
val rs1_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val rs2_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val memory_read_enable_ex = Input(Bool())
|
||||
val rd_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val memory_read_enable_mem = Input(Bool())
|
||||
val rd_mem = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val csr_start_paging = Input(Bool())
|
||||
|
||||
val if_flush = Output(Bool())
|
||||
val id_flush = Output(Bool())
|
||||
val pc_stall = Output(Bool())
|
||||
val if_stall = Output(Bool())
|
||||
val id_stall = Output(Bool())
|
||||
val ex_stall = Output(Bool())
|
||||
})
|
||||
|
||||
val id_hazard = (io.memory_read_enable_ex || io.jump_instruction_id) && io.rd_ex =/= 0.U && (io.rd_ex === io.rs1_id
|
||||
|| io.rd_ex === io.rs2_id) ||
|
||||
io.jump_instruction_id && io.memory_read_enable_mem && io.rd_mem =/= 0.U && (io.rd_mem === io.rs1_id || io.rd_mem
|
||||
=== io.rs2_id)
|
||||
io.if_flush := io.jump_flag && !id_hazard || io.csr_start_paging
|
||||
io.id_flush := id_hazard || io.csr_start_paging
|
||||
|
||||
io.pc_stall := io.stall_flag_mem || io.stall_flag_clint || id_hazard || io.stall_flag_bus || io.stall_flag_if
|
||||
io.if_stall := io.stall_flag_mem || io.stall_flag_clint || id_hazard
|
||||
io.id_stall := io.stall_flag_mem || io.stall_flag_clint
|
||||
io.ex_stall := io.stall_flag_mem || io.stall_flag_clint
|
||||
}
|
||||
115
mini-yatcpu/src/main/scala/riscv/core/fivestage/EX2MEM.scala
Normal file
115
mini-yatcpu/src/main/scala/riscv/core/fivestage/EX2MEM.scala
Normal file
@@ -0,0 +1,115 @@
|
||||
// Copyright 2022 Canbin Huang
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.fivestage
|
||||
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
|
||||
class EX2MEM extends Module {
|
||||
val io = IO(new Bundle() {
|
||||
val stall_flag = Input(Bool())
|
||||
val flush_enable = Input(Bool())
|
||||
val regs_write_enable = Input(Bool())
|
||||
val regs_write_source = Input(UInt(2.W))
|
||||
val regs_write_address = Input(UInt(Parameters.AddrWidth))
|
||||
val instruction_address = Input(UInt(Parameters.AddrWidth))
|
||||
val instruction = Input(UInt(Parameters.DataWidth))
|
||||
val reg1_data = Input(UInt(Parameters.DataWidth))
|
||||
val reg2_data = Input(UInt(Parameters.DataWidth))
|
||||
val memory_read_enable = Input(Bool())
|
||||
val memory_write_enable = Input(Bool())
|
||||
val alu_result = Input(UInt(Parameters.DataWidth))
|
||||
val csr_read_data = Input(UInt(Parameters.DataWidth))
|
||||
|
||||
val output_regs_write_enable = Output(Bool())
|
||||
val output_regs_write_source = Output(UInt(2.W))
|
||||
val output_regs_write_address = Output(UInt(Parameters.AddrWidth))
|
||||
val output_instruction_address = Output(UInt(Parameters.AddrWidth))
|
||||
val output_instruction = Output(UInt(Parameters.DataWidth))
|
||||
val output_reg1_data = Output(UInt(Parameters.DataWidth))
|
||||
val output_reg2_data = Output(UInt(Parameters.DataWidth))
|
||||
val output_memory_read_enable = Output(Bool())
|
||||
val output_memory_write_enable = Output(Bool())
|
||||
val output_alu_result = Output(UInt(Parameters.DataWidth))
|
||||
val output_csr_read_data = Output(UInt(Parameters.DataWidth))
|
||||
})
|
||||
val write_enable = !io.stall_flag
|
||||
|
||||
val regs_write_enable = Module(new PipelineRegister(1))
|
||||
regs_write_enable.io.in := io.regs_write_enable
|
||||
regs_write_enable.io.write_enable := write_enable
|
||||
regs_write_enable.io.flush_enable := io.flush_enable
|
||||
io.output_regs_write_enable := regs_write_enable.io.out
|
||||
|
||||
val regs_write_source = Module(new PipelineRegister(2))
|
||||
regs_write_source.io.in := io.regs_write_source
|
||||
regs_write_source.io.write_enable := write_enable
|
||||
regs_write_source.io.flush_enable := io.flush_enable
|
||||
io.output_regs_write_source := regs_write_source.io.out
|
||||
|
||||
val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits))
|
||||
regs_write_address.io.in := io.regs_write_address
|
||||
regs_write_address.io.write_enable := write_enable
|
||||
regs_write_address.io.flush_enable := io.flush_enable
|
||||
io.output_regs_write_address := regs_write_address.io.out
|
||||
|
||||
val instruction_address = Module(new PipelineRegister(Parameters.AddrBits))
|
||||
instruction_address.io.in := io.instruction_address
|
||||
instruction_address.io.write_enable := write_enable
|
||||
instruction_address.io.flush_enable := io.flush_enable
|
||||
io.output_instruction_address := instruction_address.io.out
|
||||
|
||||
val instruction = Module(new PipelineRegister(Parameters.InstructionBits))
|
||||
instruction.io.in := io.instruction
|
||||
instruction.io.write_enable := write_enable
|
||||
instruction.io.flush_enable := io.flush_enable
|
||||
io.output_instruction := instruction.io.out
|
||||
|
||||
val reg1_data = Module(new PipelineRegister())
|
||||
reg1_data.io.in := io.reg1_data
|
||||
reg1_data.io.write_enable := write_enable
|
||||
reg1_data.io.flush_enable := io.flush_enable
|
||||
io.output_reg1_data := reg1_data.io.out
|
||||
|
||||
val reg2_data = Module(new PipelineRegister())
|
||||
reg2_data.io.in := io.reg2_data
|
||||
reg2_data.io.write_enable := write_enable
|
||||
reg2_data.io.flush_enable := io.flush_enable
|
||||
io.output_reg2_data := reg2_data.io.out
|
||||
|
||||
val alu_result = Module(new PipelineRegister())
|
||||
alu_result.io.in := io.alu_result
|
||||
alu_result.io.write_enable := write_enable
|
||||
alu_result.io.flush_enable := io.flush_enable
|
||||
io.output_alu_result := alu_result.io.out
|
||||
|
||||
val memory_read_enable = Module(new PipelineRegister(1))
|
||||
memory_read_enable.io.in := io.memory_read_enable
|
||||
memory_read_enable.io.write_enable := write_enable
|
||||
memory_read_enable.io.flush_enable := io.flush_enable
|
||||
io.output_memory_read_enable := memory_read_enable.io.out
|
||||
|
||||
val memory_write_enable = Module(new PipelineRegister(1))
|
||||
memory_write_enable.io.in := io.memory_write_enable
|
||||
memory_write_enable.io.write_enable := write_enable
|
||||
memory_write_enable.io.flush_enable := io.flush_enable
|
||||
io.output_memory_write_enable := memory_write_enable.io.out
|
||||
|
||||
val csr_read_data = Module(new PipelineRegister())
|
||||
csr_read_data.io.in := io.csr_read_data
|
||||
csr_read_data.io.write_enable := write_enable
|
||||
csr_read_data.io.flush_enable := io.flush_enable
|
||||
io.output_csr_read_data := csr_read_data.io.out
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.fivestage
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import riscv.Parameters
|
||||
|
||||
object MemoryAccessStates extends ChiselEnum {
|
||||
val Idle, Read, Write, ReadWrite = Value
|
||||
}
|
||||
|
||||
class Execute extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val instruction = Input(UInt(Parameters.InstructionWidth))
|
||||
val instruction_address = Input(UInt(Parameters.AddrWidth))
|
||||
val reg1_data = Input(UInt(Parameters.DataWidth))
|
||||
val reg2_data = Input(UInt(Parameters.DataWidth))
|
||||
val immediate = Input(UInt(Parameters.DataWidth))
|
||||
val aluop1_source = Input(UInt(1.W))
|
||||
val aluop2_source = Input(UInt(1.W))
|
||||
val csr_read_data = Input(UInt(Parameters.DataWidth))
|
||||
val forward_from_mem = Input(UInt(Parameters.DataWidth))
|
||||
val forward_from_wb = Input(UInt(Parameters.DataWidth))
|
||||
val reg1_forward = Input(UInt(2.W))
|
||||
val reg2_forward = Input(UInt(2.W))
|
||||
|
||||
val mem_alu_result = Output(UInt(Parameters.DataWidth))
|
||||
val csr_write_data = Output(UInt(Parameters.DataWidth))
|
||||
})
|
||||
|
||||
val opcode = io.instruction(6, 0)
|
||||
val funct3 = io.instruction(14, 12)
|
||||
val funct7 = io.instruction(31, 25)
|
||||
val rd = io.instruction(11, 7)
|
||||
val uimm = io.instruction(19, 15)
|
||||
|
||||
val alu = Module(new ALU)
|
||||
val alu_ctrl = Module(new ALUControl)
|
||||
|
||||
alu_ctrl.io.opcode := opcode
|
||||
alu_ctrl.io.funct3 := funct3
|
||||
alu_ctrl.io.funct7 := funct7
|
||||
alu.io.func := alu_ctrl.io.alu_funct
|
||||
alu.io.op1 := Mux(
|
||||
io.aluop1_source === ALUOp1Source.InstructionAddress,
|
||||
io.instruction_address,
|
||||
MuxLookup(io.reg1_forward, io.reg1_data)(
|
||||
IndexedSeq(
|
||||
ForwardingType.ForwardFromMEM -> io.forward_from_mem,
|
||||
ForwardingType.ForwardFromWB -> io.forward_from_wb
|
||||
)
|
||||
)
|
||||
)
|
||||
alu.io.op2 := Mux(
|
||||
io.aluop2_source === ALUOp2Source.Immediate,
|
||||
io.immediate,
|
||||
MuxLookup(io.reg2_forward, io.reg2_data)(
|
||||
IndexedSeq(
|
||||
ForwardingType.ForwardFromMEM -> io.forward_from_mem,
|
||||
ForwardingType.ForwardFromWB -> io.forward_from_wb
|
||||
)
|
||||
)
|
||||
)
|
||||
io.mem_alu_result := alu.io.result
|
||||
io.csr_write_data := MuxLookup(funct3, 0.U)(IndexedSeq(
|
||||
InstructionsTypeCSR.csrrw -> io.reg1_data,
|
||||
InstructionsTypeCSR.csrrc -> io.csr_read_data.&((~io.reg1_data).asUInt),
|
||||
InstructionsTypeCSR.csrrs -> io.csr_read_data.|(io.reg1_data),
|
||||
InstructionsTypeCSR.csrrwi -> Cat(0.U(27.W), uimm),
|
||||
InstructionsTypeCSR.csrrci -> io.csr_read_data.&((~Cat(0.U(27.W), uimm)).asUInt),
|
||||
InstructionsTypeCSR.csrrsi -> io.csr_read_data.|(Cat(0.U(27.W), uimm)),
|
||||
))
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright 2022 Canbin Huang
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.fivestage
|
||||
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
|
||||
object ForwardingType {
|
||||
val NoForward = 0.U(2.W)
|
||||
val ForwardFromMEM = 1.U(2.W)
|
||||
val ForwardFromWB = 2.U(2.W)
|
||||
}
|
||||
|
||||
class Forwarding extends Module {
|
||||
val io = IO(new Bundle() {
|
||||
val rs1_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val rs2_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val rs1_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val rs2_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val rd_mem = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val reg_write_enable_mem = Input(Bool())
|
||||
val rd_wb = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val reg_write_enable_wb = Input(Bool())
|
||||
|
||||
val reg1_forward_id = Output(UInt(2.W))
|
||||
val reg2_forward_id = Output(UInt(2.W))
|
||||
val reg1_forward_ex = Output(UInt(2.W))
|
||||
val reg2_forward_ex = Output(UInt(2.W))
|
||||
})
|
||||
|
||||
when(io.reg_write_enable_mem && io.rd_mem =/= 0.U && io.rd_mem === io.rs1_id) {
|
||||
io.reg1_forward_id := ForwardingType.ForwardFromMEM
|
||||
}.elsewhen(io.reg_write_enable_wb && io.rd_wb =/= 0.U && io.rd_wb === io.rs1_id) {
|
||||
io.reg1_forward_id := ForwardingType.ForwardFromWB
|
||||
}.otherwise {
|
||||
io.reg1_forward_id := ForwardingType.NoForward
|
||||
}
|
||||
|
||||
when(io.reg_write_enable_mem && io.rd_mem =/= 0.U && io.rd_mem === io.rs2_id) {
|
||||
io.reg2_forward_id := ForwardingType.ForwardFromMEM
|
||||
}.elsewhen(io.reg_write_enable_wb && io.rd_wb =/= 0.U && io.rd_wb === io.rs2_id) {
|
||||
io.reg2_forward_id := ForwardingType.ForwardFromWB
|
||||
}.otherwise {
|
||||
io.reg2_forward_id := ForwardingType.NoForward
|
||||
}
|
||||
|
||||
when(io.reg_write_enable_mem && io.rd_mem =/= 0.U && io.rd_mem === io.rs1_ex) {
|
||||
io.reg1_forward_ex := ForwardingType.ForwardFromMEM
|
||||
}.elsewhen(io.reg_write_enable_wb && io.rd_wb =/= 0.U && io.rd_wb === io.rs1_ex) {
|
||||
io.reg1_forward_ex := ForwardingType.ForwardFromWB
|
||||
}.otherwise {
|
||||
io.reg1_forward_ex := ForwardingType.NoForward
|
||||
}
|
||||
|
||||
when(io.reg_write_enable_mem && io.rd_mem =/= 0.U && io.rd_mem === io.rs2_ex) {
|
||||
io.reg2_forward_ex := ForwardingType.ForwardFromMEM
|
||||
}.elsewhen(io.reg_write_enable_wb && io.rd_wb =/= 0.U && io.rd_wb === io.rs2_ex) {
|
||||
io.reg2_forward_ex := ForwardingType.ForwardFromWB
|
||||
}.otherwise {
|
||||
io.reg2_forward_ex := ForwardingType.NoForward
|
||||
}
|
||||
}
|
||||
147
mini-yatcpu/src/main/scala/riscv/core/fivestage/ID2EX.scala
Normal file
147
mini-yatcpu/src/main/scala/riscv/core/fivestage/ID2EX.scala
Normal file
@@ -0,0 +1,147 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.fivestage
|
||||
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
|
||||
class ID2EX extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val stall_flag = Input(Bool())
|
||||
val flush_enable = Input(Bool())
|
||||
val instruction = Input(UInt(Parameters.InstructionWidth))
|
||||
val instruction_address = Input(UInt(Parameters.AddrWidth))
|
||||
val regs_write_enable = Input(Bool())
|
||||
val regs_write_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val regs_write_source = Input(UInt(2.W))
|
||||
val reg1_data = Input(UInt(Parameters.DataWidth))
|
||||
val reg2_data = Input(UInt(Parameters.DataWidth))
|
||||
val immediate = Input(UInt(Parameters.DataWidth))
|
||||
val aluop1_source = Input(UInt(1.W))
|
||||
val aluop2_source = Input(UInt(1.W))
|
||||
val csr_write_enable = Input(Bool())
|
||||
val csr_address = Input(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val memory_read_enable = Input(Bool())
|
||||
val memory_write_enable = Input(Bool())
|
||||
val csr_read_data = Input(UInt(Parameters.DataWidth))
|
||||
|
||||
val output_instruction = Output(UInt(Parameters.DataWidth))
|
||||
val output_instruction_address = Output(UInt(Parameters.AddrWidth))
|
||||
val output_regs_write_enable = Output(Bool())
|
||||
val output_regs_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val output_regs_write_source = Output(UInt(2.W))
|
||||
val output_reg1_data = Output(UInt(Parameters.DataWidth))
|
||||
val output_reg2_data = Output(UInt(Parameters.DataWidth))
|
||||
val output_immediate = Output(UInt(Parameters.DataWidth))
|
||||
val output_aluop1_source = Output(UInt(1.W))
|
||||
val output_aluop2_source = Output(UInt(1.W))
|
||||
val output_csr_write_enable = Output(Bool())
|
||||
val output_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val output_memory_read_enable = Output(Bool())
|
||||
val output_memory_write_enable = Output(Bool())
|
||||
val output_csr_read_data = Output(UInt(Parameters.DataWidth))
|
||||
})
|
||||
val write_enable = !io.stall_flag
|
||||
|
||||
val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop))
|
||||
instruction.io.in := io.instruction
|
||||
instruction.io.write_enable := write_enable
|
||||
instruction.io.flush_enable := io.flush_enable
|
||||
io.output_instruction := instruction.io.out
|
||||
|
||||
val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress))
|
||||
instruction_address.io.in := io.instruction_address
|
||||
instruction_address.io.write_enable := write_enable
|
||||
instruction_address.io.flush_enable := io.flush_enable
|
||||
io.output_instruction_address := instruction_address.io.out
|
||||
|
||||
val regs_write_enable = Module(new PipelineRegister(1))
|
||||
regs_write_enable.io.in := io.regs_write_enable
|
||||
regs_write_enable.io.write_enable := write_enable
|
||||
regs_write_enable.io.flush_enable := io.flush_enable
|
||||
io.output_regs_write_enable := regs_write_enable.io.out
|
||||
|
||||
val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits))
|
||||
regs_write_address.io.in := io.regs_write_address
|
||||
regs_write_address.io.write_enable := write_enable
|
||||
regs_write_address.io.flush_enable := io.flush_enable
|
||||
io.output_regs_write_address := regs_write_address.io.out
|
||||
|
||||
val regs_write_source = Module(new PipelineRegister(2))
|
||||
regs_write_source.io.in := io.regs_write_source
|
||||
regs_write_source.io.write_enable := write_enable
|
||||
regs_write_source.io.flush_enable := io.flush_enable
|
||||
io.output_regs_write_source := regs_write_source.io.out
|
||||
|
||||
val reg1_data = Module(new PipelineRegister())
|
||||
reg1_data.io.in := io.reg1_data
|
||||
reg1_data.io.write_enable := write_enable
|
||||
reg1_data.io.flush_enable := io.flush_enable
|
||||
io.output_reg1_data := reg1_data.io.out
|
||||
|
||||
val reg2_data = Module(new PipelineRegister())
|
||||
reg2_data.io.in := io.reg2_data
|
||||
reg2_data.io.write_enable := write_enable
|
||||
reg2_data.io.flush_enable := io.flush_enable
|
||||
io.output_reg2_data := reg2_data.io.out
|
||||
|
||||
val immediate = Module(new PipelineRegister())
|
||||
immediate.io.in := io.immediate
|
||||
immediate.io.write_enable := write_enable
|
||||
immediate.io.flush_enable := io.flush_enable
|
||||
io.output_immediate := immediate.io.out
|
||||
|
||||
val aluop1_source = Module(new PipelineRegister(1))
|
||||
aluop1_source.io.in := io.aluop1_source
|
||||
aluop1_source.io.write_enable := write_enable
|
||||
aluop1_source.io.flush_enable := io.flush_enable
|
||||
io.output_aluop1_source := aluop1_source.io.out
|
||||
|
||||
val aluop2_source = Module(new PipelineRegister(1))
|
||||
aluop2_source.io.in := io.aluop2_source
|
||||
aluop2_source.io.write_enable := write_enable
|
||||
aluop2_source.io.flush_enable := io.flush_enable
|
||||
io.output_aluop2_source := aluop2_source.io.out
|
||||
|
||||
val csr_write_enable = Module(new PipelineRegister(1))
|
||||
csr_write_enable.io.in := io.csr_write_enable
|
||||
csr_write_enable.io.write_enable := write_enable
|
||||
csr_write_enable.io.flush_enable := io.flush_enable
|
||||
io.output_csr_write_enable := csr_write_enable.io.out
|
||||
|
||||
val csr_address = Module(new PipelineRegister(Parameters.CSRRegisterAddrBits))
|
||||
csr_address.io.in := io.csr_address
|
||||
csr_address.io.write_enable := write_enable
|
||||
csr_address.io.flush_enable := io.flush_enable
|
||||
io.output_csr_address := csr_address.io.out
|
||||
|
||||
val memory_read_enable = Module(new PipelineRegister(1))
|
||||
memory_read_enable.io.in := io.memory_read_enable
|
||||
memory_read_enable.io.write_enable := write_enable
|
||||
memory_read_enable.io.flush_enable := io.flush_enable
|
||||
io.output_memory_read_enable := memory_read_enable.io.out
|
||||
|
||||
val memory_write_enable = Module(new PipelineRegister(1))
|
||||
memory_write_enable.io.in := io.memory_write_enable
|
||||
memory_write_enable.io.write_enable := write_enable
|
||||
memory_write_enable.io.flush_enable := io.flush_enable
|
||||
io.output_memory_write_enable := memory_write_enable.io.out
|
||||
|
||||
val csr_read_data = Module(new PipelineRegister())
|
||||
csr_read_data.io.in := io.csr_read_data
|
||||
csr_read_data.io.write_enable := write_enable
|
||||
csr_read_data.io.flush_enable := io.flush_enable
|
||||
io.output_csr_read_data := csr_read_data.io.out
|
||||
}
|
||||
52
mini-yatcpu/src/main/scala/riscv/core/fivestage/IF2ID.scala
Normal file
52
mini-yatcpu/src/main/scala/riscv/core/fivestage/IF2ID.scala
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.fivestage
|
||||
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
|
||||
class IF2ID extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val stall_flag = Input(Bool())
|
||||
val flush_enable = Input(Bool())
|
||||
val instruction = Input(UInt(Parameters.InstructionWidth))
|
||||
val instruction_address = Input(UInt(Parameters.AddrWidth))
|
||||
val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth))
|
||||
|
||||
val output_instruction = Output(UInt(Parameters.DataWidth))
|
||||
val output_instruction_address = Output(UInt(Parameters.AddrWidth))
|
||||
val output_interrupt_flag = Output(UInt(Parameters.InterruptFlagWidth))
|
||||
})
|
||||
|
||||
val write_enable = !io.stall_flag
|
||||
|
||||
val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop))
|
||||
instruction.io.in := io.instruction
|
||||
instruction.io.write_enable := write_enable
|
||||
instruction.io.flush_enable := io.flush_enable
|
||||
io.output_instruction := instruction.io.out
|
||||
|
||||
val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress))
|
||||
instruction_address.io.in := io.instruction_address
|
||||
instruction_address.io.write_enable := write_enable
|
||||
instruction_address.io.flush_enable := io.flush_enable
|
||||
io.output_instruction_address := instruction_address.io.out
|
||||
|
||||
val interrupt_flag = Module(new PipelineRegister(Parameters.InterruptFlagBits))
|
||||
interrupt_flag.io.in := io.interrupt_flag
|
||||
interrupt_flag.io.write_enable := write_enable
|
||||
interrupt_flag.io.flush_enable := io.flush_enable
|
||||
io.output_interrupt_flag := interrupt_flag.io.out
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.fivestage
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import riscv.Parameters
|
||||
|
||||
object InstructionTypes {
|
||||
val L = "b0000011".U
|
||||
val I = "b0010011".U
|
||||
val S = "b0100011".U
|
||||
val RM = "b0110011".U
|
||||
val B = "b1100011".U
|
||||
}
|
||||
|
||||
object Instructions {
|
||||
val lui = "b0110111".U
|
||||
val nop = "b0000001".U
|
||||
val jal = "b1101111".U
|
||||
val jalr = "b1100111".U
|
||||
val auipc = "b0010111".U
|
||||
val csr = "b1110011".U
|
||||
val fence = "b0001111".U
|
||||
}
|
||||
|
||||
object InstructionsTypeL {
|
||||
val lb = "b000".U
|
||||
val lh = "b001".U
|
||||
val lw = "b010".U
|
||||
val lbu = "b100".U
|
||||
val lhu = "b101".U
|
||||
}
|
||||
|
||||
object InstructionsTypeI {
|
||||
val addi = 0.U
|
||||
val slli = 1.U
|
||||
val slti = 2.U
|
||||
val sltiu = 3.U
|
||||
val xori = 4.U
|
||||
val sri = 5.U
|
||||
val ori = 6.U
|
||||
val andi = 7.U
|
||||
}
|
||||
|
||||
object InstructionsTypeS {
|
||||
val sb = "b000".U
|
||||
val sh = "b001".U
|
||||
val sw = "b010".U
|
||||
}
|
||||
|
||||
object InstructionsTypeR {
|
||||
val add_sub = 0.U
|
||||
val sll = 1.U
|
||||
val slt = 2.U
|
||||
val sltu = 3.U
|
||||
val xor = 4.U
|
||||
val sr = 5.U
|
||||
val or = 6.U
|
||||
val and = 7.U
|
||||
}
|
||||
|
||||
object InstructionsTypeM {
|
||||
val mul = 0.U
|
||||
val mulh = 1.U
|
||||
val mulhsu = 2.U
|
||||
val mulhum = 3.U
|
||||
val div = 4.U
|
||||
val divu = 5.U
|
||||
val rem = 6.U
|
||||
val remu = 7.U
|
||||
}
|
||||
|
||||
object InstructionsTypeB {
|
||||
val beq = "b000".U
|
||||
val bne = "b001".U
|
||||
val blt = "b100".U
|
||||
val bge = "b101".U
|
||||
val bltu = "b110".U
|
||||
val bgeu = "b111".U
|
||||
}
|
||||
|
||||
object InstructionsTypeCSR {
|
||||
val csrrw = "b001".U
|
||||
val csrrs = "b010".U
|
||||
val csrrc = "b011".U
|
||||
val csrrwi = "b101".U
|
||||
val csrrsi = "b110".U
|
||||
val csrrci = "b111".U
|
||||
}
|
||||
|
||||
object InstructionsNop {
|
||||
val nop = 0x00000013L.U(Parameters.DataWidth)
|
||||
}
|
||||
|
||||
object InstructionsRet {
|
||||
val mret = 0x30200073L.U(Parameters.DataWidth)
|
||||
val ret = 0x00008067L.U(Parameters.DataWidth)
|
||||
}
|
||||
|
||||
object InstructionsEnv {
|
||||
val ecall = 0x00000073L.U(Parameters.DataWidth)
|
||||
val ebreak = 0x00100073L.U(Parameters.DataWidth)
|
||||
}
|
||||
|
||||
object ALUOp1Source {
|
||||
val Register = 0.U(1.W)
|
||||
val InstructionAddress = 1.U(1.W)
|
||||
}
|
||||
|
||||
object ALUOp2Source {
|
||||
val Register = 0.U(1.W)
|
||||
val Immediate = 1.U(1.W)
|
||||
}
|
||||
|
||||
object RegWriteSource {
|
||||
val ALUResult = 0.U(2.W)
|
||||
val Memory = 1.U(2.W)
|
||||
val CSR = 2.U(2.W)
|
||||
val NextInstructionAddress = 3.U(2.W)
|
||||
}
|
||||
|
||||
class InstructionDecode extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val instruction = Input(UInt(Parameters.InstructionWidth))
|
||||
val instruction_address = Input(UInt(Parameters.AddrWidth))
|
||||
val reg1_data = Input(UInt(Parameters.DataWidth))
|
||||
val reg2_data = Input(UInt(Parameters.DataWidth))
|
||||
val forward_from_mem = Input(UInt(Parameters.DataWidth))
|
||||
val forward_from_wb = Input(UInt(Parameters.DataWidth))
|
||||
val reg1_forward = Input(UInt(2.W))
|
||||
val reg2_forward = Input(UInt(2.W))
|
||||
val interrupt_assert = Input(Bool())
|
||||
val interrupt_handler_address = Input(UInt(Parameters.AddrWidth))
|
||||
|
||||
val regs_reg1_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val regs_reg2_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val ex_reg1_data = Output(UInt(Parameters.DataWidth))
|
||||
val ex_reg2_data = Output(UInt(Parameters.DataWidth))
|
||||
val ex_immediate = Output(UInt(Parameters.DataWidth))
|
||||
val ex_aluop1_source = Output(UInt(1.W))
|
||||
val ex_aluop2_source = Output(UInt(1.W))
|
||||
val ex_memory_read_enable = Output(Bool())
|
||||
val ex_memory_write_enable = Output(Bool())
|
||||
val ex_reg_write_source = Output(UInt(2.W))
|
||||
val ex_reg_write_enable = Output(Bool())
|
||||
val ex_reg_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val ex_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val ex_csr_write_enable = Output(Bool())
|
||||
val ctrl_jump_instruction = Output(Bool())
|
||||
val clint_jump_flag = Output(Bool())
|
||||
val clint_jump_address = Output(UInt(Parameters.AddrWidth))
|
||||
val if_jump_flag = Output(Bool())
|
||||
val if_jump_address = Output(UInt(Parameters.AddrWidth))
|
||||
})
|
||||
val opcode = io.instruction(6, 0)
|
||||
val funct3 = io.instruction(14, 12)
|
||||
val funct7 = io.instruction(31, 25)
|
||||
val rd = io.instruction(11, 7)
|
||||
val rs1 = io.instruction(19, 15)
|
||||
val rs2 = io.instruction(24, 20)
|
||||
|
||||
io.regs_reg1_read_address := Mux(opcode === Instructions.lui, 0.U(Parameters.PhysicalRegisterAddrWidth), rs1)
|
||||
io.regs_reg2_read_address := rs2
|
||||
io.ex_reg1_data := io.reg1_data
|
||||
io.ex_reg2_data := io.reg2_data
|
||||
io.ex_immediate := MuxLookup(opcode, Cat(Fill(20, io.instruction(31)), io.instruction(31, 20)))(
|
||||
IndexedSeq(
|
||||
InstructionTypes.I -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)),
|
||||
InstructionTypes.L -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)),
|
||||
Instructions.jalr -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)),
|
||||
InstructionTypes.S -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 25), io.instruction(11, 7)),
|
||||
InstructionTypes.B -> Cat(Fill(20, io.instruction(31)), io.instruction(7), io.instruction(30, 25), io
|
||||
.instruction(11, 8), 0.U(1.W)),
|
||||
Instructions.lui -> Cat(io.instruction(31, 12), 0.U(12.W)),
|
||||
Instructions.auipc -> Cat(io.instruction(31, 12), 0.U(12.W)),
|
||||
Instructions.jal -> Cat(Fill(12, io.instruction(31)), io.instruction(19, 12), io.instruction(20), io
|
||||
.instruction(30, 21), 0.U(1.W))
|
||||
)
|
||||
)
|
||||
io.ex_aluop1_source := Mux(
|
||||
opcode === Instructions.auipc || opcode === InstructionTypes.B || opcode === Instructions.jal,
|
||||
ALUOp1Source.InstructionAddress,
|
||||
ALUOp1Source.Register
|
||||
)
|
||||
io.ex_aluop2_source := Mux(
|
||||
opcode === InstructionTypes.RM,
|
||||
ALUOp2Source.Register,
|
||||
ALUOp2Source.Immediate
|
||||
)
|
||||
io.ex_memory_read_enable := opcode === InstructionTypes.L
|
||||
io.ex_memory_write_enable := opcode === InstructionTypes.S
|
||||
io.ex_reg_write_source := MuxLookup(opcode, RegWriteSource.ALUResult)(
|
||||
IndexedSeq(
|
||||
InstructionTypes.L -> RegWriteSource.Memory,
|
||||
Instructions.csr -> RegWriteSource.CSR,
|
||||
Instructions.jal -> RegWriteSource.NextInstructionAddress,
|
||||
Instructions.jalr -> RegWriteSource.NextInstructionAddress
|
||||
)
|
||||
)
|
||||
io.ex_reg_write_enable := (opcode === InstructionTypes.RM) || (opcode === InstructionTypes.I) ||
|
||||
(opcode === InstructionTypes.L) || (opcode === Instructions.auipc) || (opcode === Instructions.lui) ||
|
||||
(opcode === Instructions.jal) || (opcode === Instructions.jalr) || (opcode === Instructions.csr)
|
||||
io.ex_reg_write_address := io.instruction(11, 7)
|
||||
io.ex_csr_address := io.instruction(31, 20)
|
||||
io.ex_csr_write_enable := (opcode === Instructions.csr) && (
|
||||
funct3 === InstructionsTypeCSR.csrrw || funct3 === InstructionsTypeCSR.csrrwi ||
|
||||
funct3 === InstructionsTypeCSR.csrrs || funct3 === InstructionsTypeCSR.csrrsi ||
|
||||
funct3 === InstructionsTypeCSR.csrrc || funct3 === InstructionsTypeCSR.csrrci
|
||||
)
|
||||
|
||||
val reg1_data = MuxLookup(io.reg1_forward, io.reg1_data)(
|
||||
IndexedSeq(
|
||||
ForwardingType.ForwardFromMEM -> io.forward_from_mem,
|
||||
ForwardingType.ForwardFromWB -> io.forward_from_wb
|
||||
)
|
||||
)
|
||||
val reg2_data = MuxLookup(io.reg2_forward, io.reg2_data)(
|
||||
IndexedSeq(
|
||||
ForwardingType.ForwardFromMEM -> io.forward_from_mem,
|
||||
ForwardingType.ForwardFromWB -> io.forward_from_wb
|
||||
)
|
||||
)
|
||||
io.ctrl_jump_instruction := (opcode === Instructions.jal) ||
|
||||
(opcode === Instructions.jalr) || (opcode === InstructionTypes.B)
|
||||
val instruction_jump_flag = (opcode === Instructions.jal) ||
|
||||
(opcode === Instructions.jalr) ||
|
||||
(opcode === InstructionTypes.B) && MuxLookup(funct3, false.B)(
|
||||
IndexedSeq(
|
||||
InstructionsTypeB.beq -> (reg1_data === reg2_data),
|
||||
InstructionsTypeB.bne -> (reg1_data =/= reg2_data),
|
||||
InstructionsTypeB.blt -> (reg1_data.asSInt < reg2_data.asSInt),
|
||||
InstructionsTypeB.bge -> (reg1_data.asSInt >= reg2_data.asSInt),
|
||||
InstructionsTypeB.bltu -> (reg1_data.asUInt < reg2_data.asUInt),
|
||||
InstructionsTypeB.bgeu -> (reg1_data.asUInt >= reg2_data.asUInt)
|
||||
)
|
||||
)
|
||||
val instruction_jump_address = io.ex_immediate + Mux(opcode === Instructions.jalr, reg1_data, io.instruction_address)
|
||||
io.clint_jump_flag := instruction_jump_flag
|
||||
io.clint_jump_address := instruction_jump_address
|
||||
io.if_jump_flag := io.interrupt_assert || instruction_jump_flag
|
||||
io.if_jump_address := Mux(io.interrupt_assert,
|
||||
io.interrupt_handler_address,
|
||||
instruction_jump_address
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.fivestage
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util.MuxCase
|
||||
import riscv.Parameters
|
||||
import riscv.core.BusBundle
|
||||
|
||||
object ProgramCounter {
|
||||
val EntryAddress = Parameters.EntryAddress
|
||||
}
|
||||
|
||||
object IFAccessStates extends ChiselEnum {
|
||||
val idle, read = Value
|
||||
}
|
||||
|
||||
class InstructionFetch extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val stall_flag_ctrl = Input(Bool())
|
||||
val jump_flag_id = Input(Bool())
|
||||
val jump_address_id = Input(UInt(Parameters.AddrWidth))
|
||||
|
||||
val physical_address = Input(UInt(Parameters.AddrWidth))
|
||||
|
||||
val ctrl_stall_flag = Output(Bool())
|
||||
val id_instruction_address = Output(UInt(Parameters.AddrWidth))
|
||||
val id_instruction = Output(UInt(Parameters.InstructionWidth))
|
||||
val pc_valid = Output(Bool())
|
||||
|
||||
val bus = new BusBundle
|
||||
})
|
||||
val pending_jump = RegInit(false.B)
|
||||
val pc = RegInit(ProgramCounter.EntryAddress)
|
||||
val state = RegInit(IFAccessStates.idle)
|
||||
val pc_valid = RegInit(false.B) //because the romloader of verilator(sim_main.cpp) need no time cycle
|
||||
//it prevent fetching instruction from 0x0, when pc haven't been initailized
|
||||
|
||||
io.bus.read := false.B
|
||||
io.bus.request := true.B
|
||||
io.bus.write := false.B
|
||||
io.bus.write_data := 0.U
|
||||
io.bus.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B))
|
||||
io.pc_valid := pc_valid
|
||||
|
||||
when(!pc_valid && pc === ProgramCounter.EntryAddress) {
|
||||
pc_valid := true.B
|
||||
}
|
||||
|
||||
pc := MuxCase(
|
||||
pc + 4.U,
|
||||
IndexedSeq(
|
||||
io.jump_flag_id -> io.jump_address_id,
|
||||
io.stall_flag_ctrl -> pc
|
||||
)
|
||||
)
|
||||
|
||||
when(!io.bus.read_valid) {
|
||||
when(io.jump_flag_id) {
|
||||
pending_jump := true.B
|
||||
}
|
||||
}
|
||||
|
||||
when(io.bus.read_valid) {
|
||||
when(pending_jump) {
|
||||
pending_jump := false.B
|
||||
}
|
||||
}
|
||||
|
||||
when(io.bus.granted) {
|
||||
when(state === IFAccessStates.idle) {
|
||||
io.bus.request := true.B
|
||||
io.bus.read := true.B
|
||||
state := IFAccessStates.read
|
||||
}.elsewhen(state === IFAccessStates.read) {
|
||||
io.bus.read := false.B
|
||||
io.bus.request := true.B
|
||||
when(io.bus.read_valid) {
|
||||
state := IFAccessStates.idle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
io.id_instruction := Mux(
|
||||
io.bus.read_valid && !pending_jump && !io.jump_flag_id,
|
||||
io.bus.read_data,
|
||||
InstructionsNop.nop
|
||||
)
|
||||
io.ctrl_stall_flag := !io.bus.read_valid || pending_jump
|
||||
io.id_instruction_address := pc
|
||||
io.bus.address := io.physical_address
|
||||
}
|
||||
82
mini-yatcpu/src/main/scala/riscv/core/fivestage/MEM2WB.scala
Normal file
82
mini-yatcpu/src/main/scala/riscv/core/fivestage/MEM2WB.scala
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright 2022 Canbin Huang
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.fivestage
|
||||
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
|
||||
class MEM2WB extends Module {
|
||||
val io = IO(new Bundle() {
|
||||
val instruction_address = Input(UInt(Parameters.AddrWidth))
|
||||
val alu_result = Input(UInt(Parameters.DataWidth))
|
||||
val regs_write_enable = Input(Bool())
|
||||
val regs_write_source = Input(UInt(2.W))
|
||||
val regs_write_address = Input(UInt(Parameters.AddrWidth))
|
||||
val memory_read_data = Input(UInt(Parameters.DataWidth))
|
||||
val csr_read_data = Input(UInt(Parameters.DataWidth))
|
||||
|
||||
val output_instruction_address = Output(UInt(Parameters.AddrWidth))
|
||||
val output_alu_result = Output(UInt(Parameters.DataWidth))
|
||||
val output_regs_write_enable = Output(Bool())
|
||||
val output_regs_write_source = Output(UInt(2.W))
|
||||
val output_regs_write_address = Output(UInt(Parameters.AddrWidth))
|
||||
val output_memory_read_data = Output(UInt(Parameters.DataWidth))
|
||||
val output_csr_read_data = Output(UInt(Parameters.DataWidth))
|
||||
})
|
||||
val flush_enable = false.B
|
||||
val write_enable = true.B
|
||||
|
||||
val alu_result = Module(new PipelineRegister())
|
||||
alu_result.io.in := io.alu_result
|
||||
alu_result.io.write_enable := write_enable
|
||||
alu_result.io.flush_enable := flush_enable
|
||||
io.output_alu_result := alu_result.io.out
|
||||
|
||||
val memory_read_data = Module(new PipelineRegister())
|
||||
memory_read_data.io.in := io.memory_read_data
|
||||
memory_read_data.io.write_enable := write_enable
|
||||
memory_read_data.io.flush_enable := flush_enable
|
||||
io.output_memory_read_data := memory_read_data.io.out
|
||||
|
||||
val regs_write_enable = Module(new PipelineRegister(1))
|
||||
regs_write_enable.io.in := io.regs_write_enable
|
||||
regs_write_enable.io.write_enable := write_enable
|
||||
regs_write_enable.io.flush_enable := flush_enable
|
||||
io.output_regs_write_enable := regs_write_enable.io.out
|
||||
|
||||
val regs_write_source = Module(new PipelineRegister(2))
|
||||
regs_write_source.io.in := io.regs_write_source
|
||||
regs_write_source.io.write_enable := write_enable
|
||||
regs_write_source.io.flush_enable := flush_enable
|
||||
io.output_regs_write_source := regs_write_source.io.out
|
||||
|
||||
val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits))
|
||||
regs_write_address.io.in := io.regs_write_address
|
||||
regs_write_address.io.write_enable := write_enable
|
||||
regs_write_address.io.flush_enable := flush_enable
|
||||
io.output_regs_write_address := regs_write_address.io.out
|
||||
|
||||
val instruction_address = Module(new PipelineRegister(Parameters.InstructionBits))
|
||||
instruction_address.io.in := io.instruction_address
|
||||
instruction_address.io.write_enable := write_enable
|
||||
instruction_address.io.flush_enable := flush_enable
|
||||
io.output_instruction_address := instruction_address.io.out
|
||||
|
||||
val csr_read_data = Module(new PipelineRegister())
|
||||
csr_read_data.io.in := io.csr_read_data
|
||||
csr_read_data.io.write_enable := write_enable
|
||||
csr_read_data.io.flush_enable := flush_enable
|
||||
io.output_csr_read_data := csr_read_data.io.out
|
||||
}
|
||||
198
mini-yatcpu/src/main/scala/riscv/core/fivestage/MMU.scala
Normal file
198
mini-yatcpu/src/main/scala/riscv/core/fivestage/MMU.scala
Normal file
@@ -0,0 +1,198 @@
|
||||
package riscv.core.fivestage
|
||||
|
||||
import chisel3.util._
|
||||
import chisel3.{when, _}
|
||||
import riscv.Parameters
|
||||
import riscv.core.BusBundle
|
||||
|
||||
|
||||
object MMUStates extends ChiselEnum {
|
||||
val idle, level1, checkpte1, level0, checkpte0, setADbit, gotPhyicalAddress = Value
|
||||
}
|
||||
|
||||
class MMU extends Module {
|
||||
val io = IO(new Bundle() {
|
||||
val instructions = Input(UInt(Parameters.InstructionWidth))
|
||||
val instructions_address = Input(UInt(Parameters.AddrWidth))
|
||||
|
||||
//from satp
|
||||
val ppn_from_satp = Input(UInt(20.W))
|
||||
|
||||
val virtual_address = Input(UInt(Parameters.AddrWidth))
|
||||
val mmu_occupied_by_mem = Input(Bool())
|
||||
val restart = Input(Bool())
|
||||
val restart_done = Output(Bool())
|
||||
|
||||
val pa_valid = Output(Bool())
|
||||
val pa = Output(UInt(Parameters.AddrWidth))
|
||||
|
||||
val page_fault_signals = Output(Bool())
|
||||
val va_cause_page_fault = Output(UInt(Parameters.AddrWidth))
|
||||
val ecause = Output(UInt(Parameters.DataWidth))
|
||||
val epc = Output(UInt(Parameters.AddrWidth))
|
||||
val page_fault_responed = Input(Bool())
|
||||
|
||||
val bus = new BusBundle()
|
||||
})
|
||||
val opcode = io.instructions(6, 0)
|
||||
|
||||
val state = RegInit(MMUStates.idle)
|
||||
|
||||
val pa = RegInit(UInt(Parameters.AddrWidth), 0.U)
|
||||
val va = io.virtual_address
|
||||
val vpn1 = va(31, 22)
|
||||
|
||||
val vpn0 = va(21, 12)
|
||||
val pageoffset = va(11, 0)
|
||||
|
||||
val pte1 = Reg(UInt(Parameters.PTEWidth))
|
||||
val pte0 = Reg(UInt(Parameters.PTEWidth))
|
||||
//add a reg to avoid Combination loop
|
||||
val page_fault_signals = RegInit(false.B)
|
||||
|
||||
def raise_page_fault(): Unit = {
|
||||
io.ecause := Mux(
|
||||
io.mmu_occupied_by_mem,
|
||||
MuxLookup(io.instructions, 10.U)(
|
||||
IndexedSeq(
|
||||
InstructionTypes.S -> 15.U,
|
||||
InstructionTypes.L -> 13.U,
|
||||
)
|
||||
),
|
||||
12.U // Instruction page fault
|
||||
)
|
||||
io.va_cause_page_fault := va //for mtval
|
||||
page_fault_signals := true.B
|
||||
io.epc := Mux( //info stored before the exception handler, will start again from this pc
|
||||
io.mmu_occupied_by_mem,
|
||||
io.instructions_address, //mem_access
|
||||
va, //IF
|
||||
)
|
||||
when(io.page_fault_responed) {
|
||||
page_fault_signals := false.B
|
||||
state := MMUStates.idle
|
||||
}
|
||||
}
|
||||
|
||||
io.pa_valid := false.B
|
||||
io.bus.request := false.B
|
||||
io.bus.read := false.B
|
||||
io.bus.address := 0.U
|
||||
io.bus.write_data := 0.U
|
||||
io.bus.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B))
|
||||
io.bus.write := false.B
|
||||
io.page_fault_signals := page_fault_signals
|
||||
|
||||
io.ecause := 0.U
|
||||
io.pa := 0.U
|
||||
io.restart_done := false.B
|
||||
io.va_cause_page_fault := 0.U
|
||||
io.epc := 0.U
|
||||
|
||||
//MMU FSM
|
||||
//our physical address bits is 32
|
||||
when(io.bus.granted) {
|
||||
when(state === MMUStates.idle) {
|
||||
//read pte from mem when the bus is free and someone needs the translation
|
||||
//mem request take precedence of IF
|
||||
io.pa_valid := false.B
|
||||
io.bus.read := true.B
|
||||
io.restart_done := false.B
|
||||
io.bus.address := ((io.ppn_from_satp << Parameters.PageOffsetBits.U).asUInt & (vpn1 << 2).asUInt) //address of
|
||||
// level 1 pte
|
||||
state := MMUStates.level1
|
||||
}.elsewhen(state === MMUStates.level1) { //don't support the huge page
|
||||
//already access the bus,wait for the pte
|
||||
io.bus.read := false.B
|
||||
when(io.bus.read_valid) {
|
||||
pte1 := io.bus.read_data
|
||||
when(io.restart) {
|
||||
io.restart_done := true.B
|
||||
state := MMUStates.idle
|
||||
}.otherwise {
|
||||
state := MMUStates.checkpte1
|
||||
}
|
||||
}
|
||||
}.elsewhen(state === MMUStates.checkpte1) {
|
||||
//todo: hrpccs :no PMA or PMP check
|
||||
when(io.restart) {
|
||||
io.restart_done := true.B
|
||||
state := MMUStates.idle
|
||||
}.elsewhen(pte1(0) === 0.U || (pte1(2, 1) === "b10".U) || (pte1(9, 8) =/= "b00".U)) {
|
||||
//raise a page-fault exception corresponding to the original access type
|
||||
raise_page_fault()
|
||||
}.otherwise {
|
||||
io.bus.read := true.B
|
||||
io.bus.address := ((pte1(29, 10) << Parameters.PageOffsetBits.U).asUInt & (vpn0 << 2).asUInt) //address of
|
||||
// level 0 pte
|
||||
when(io.bus.granted) {
|
||||
state := MMUStates.level0
|
||||
}
|
||||
}
|
||||
}.elsewhen(state === MMUStates.level0) {
|
||||
io.bus.read := false.B
|
||||
when(io.bus.read_valid) {
|
||||
pte0 := io.bus.read_data
|
||||
when(io.restart) {
|
||||
io.restart_done := true.B
|
||||
state := MMUStates.idle
|
||||
}.otherwise {
|
||||
state := MMUStates.checkpte0
|
||||
}
|
||||
}
|
||||
}.elsewhen(state === MMUStates.checkpte0) {
|
||||
when(io.restart) {
|
||||
io.restart_done := true.B
|
||||
state := MMUStates.idle
|
||||
}.elsewhen(pte0(0) === 0.U || (pte0(2, 1) === "b10".U) || (pte0(9, 8) =/= "b00".U) || (pte0(3, 1) === "b000".U)) {
|
||||
//raise a page-fault exception corresponding to the original access type
|
||||
raise_page_fault()
|
||||
}.elsewhen(pte0(1) === 1.U || pte0(3) === 1.U) {
|
||||
//we found a leaf pte
|
||||
val instructionInvalid = io.mmu_occupied_by_mem === false.B && pte0(3) === 0.U
|
||||
val storeInvalid = io.instructions(6, 0) === InstructionTypes.S && pte0(2) === 0.U
|
||||
val loadInvalid = io.instructions(6, 0) === InstructionTypes.L && pte0(1) === 0.U
|
||||
when(instructionInvalid || storeInvalid || loadInvalid) {
|
||||
//todo:hrpccs :when the privillege switch is done,please add the privillege check
|
||||
raise_page_fault()
|
||||
}.elsewhen(pte0(6) === 0.U || (pte0(7) === 0.U && io.instructions(6, 0) === InstructionTypes.S)) {
|
||||
//set the access bit and the dirty bit if the instruction is store type
|
||||
//as we currently support single core CPU,so we can ignore the concurrent pte change
|
||||
//todo:hrpccs :when someone want to have a multicore support \
|
||||
// please modify this part acording to riscv-privilege
|
||||
val setAbit = io.instructions(6, 0) === InstructionTypes.S
|
||||
io.bus.write_data := Cat(pte0(31, 8), setAbit, 1.U(1.W), pte0(5, 0))
|
||||
io.bus.write := true.B
|
||||
io.bus.address := ((pte1(29, 10) << Parameters.PageOffsetBits.U).asUInt + (vpn0 << 2).asUInt)
|
||||
for (i <- 0 until Parameters.WordSize) {
|
||||
io.bus.write_strobe(i) := true.B
|
||||
}
|
||||
state := MMUStates.setADbit
|
||||
}.otherwise {
|
||||
state := MMUStates.gotPhyicalAddress
|
||||
}
|
||||
}
|
||||
}.elsewhen(state === MMUStates.setADbit) {
|
||||
io.bus.write := false.B
|
||||
when(io.bus.write_valid) {
|
||||
when(io.restart) {
|
||||
io.restart_done := true.B
|
||||
state := MMUStates.idle
|
||||
}.otherwise {
|
||||
state := MMUStates.gotPhyicalAddress
|
||||
}
|
||||
}
|
||||
}.elsewhen(state === MMUStates.gotPhyicalAddress) {
|
||||
when(io.restart) {
|
||||
io.restart_done := true.B
|
||||
state := MMUStates.idle
|
||||
}.otherwise {
|
||||
io.pa := Cat(pte0(29, 10), pageoffset)
|
||||
io.pa_valid := true.B
|
||||
state := MMUStates.idle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
// Copyright 2022 Canbin Huang
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.fivestage
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import riscv.Parameters
|
||||
import riscv.core.BusBundle
|
||||
|
||||
class MemoryAccess extends Module {
|
||||
val io = IO(new Bundle() {
|
||||
val alu_result = Input(UInt(Parameters.DataWidth))
|
||||
val reg2_data = Input(UInt(Parameters.DataWidth))
|
||||
val memory_read_enable = Input(Bool())
|
||||
val memory_write_enable = Input(Bool())
|
||||
val funct3 = Input(UInt(3.W))
|
||||
val regs_write_source = Input(UInt(2.W))
|
||||
val csr_read_data = Input(UInt(Parameters.DataWidth))
|
||||
val clint_exception_token = Input(Bool())
|
||||
|
||||
val wb_memory_read_data = Output(UInt(Parameters.DataWidth))
|
||||
val ctrl_stall_flag = Output(Bool())
|
||||
val forward_data = Output(UInt(Parameters.DataWidth))
|
||||
|
||||
val physical_address = Input(UInt(Parameters.AddrWidth))
|
||||
|
||||
val bus = new BusBundle
|
||||
})
|
||||
val mem_address_index = io.physical_address(log2Up(Parameters.WordSize) - 1, 0)
|
||||
val mem_access_state = RegInit(MemoryAccessStates.Idle)
|
||||
|
||||
def on_bus_transaction_finished() = {
|
||||
mem_access_state := MemoryAccessStates.Idle
|
||||
io.ctrl_stall_flag := false.B
|
||||
}
|
||||
|
||||
io.bus.request := false.B
|
||||
io.bus.read := false.B
|
||||
io.bus.address := io.physical_address
|
||||
io.bus.write_data := 0.U
|
||||
io.bus.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B))
|
||||
io.bus.write := false.B
|
||||
io.wb_memory_read_data := 0.U
|
||||
io.ctrl_stall_flag := false.B
|
||||
|
||||
when(io.clint_exception_token) {
|
||||
io.bus.request := false.B
|
||||
io.ctrl_stall_flag := false.B
|
||||
}.elsewhen(io.memory_read_enable) {
|
||||
when(mem_access_state === MemoryAccessStates.Idle) {
|
||||
// Start the read transaction when the bus is available
|
||||
io.ctrl_stall_flag := true.B
|
||||
io.bus.read := true.B
|
||||
io.bus.request := true.B
|
||||
when(io.bus.granted) {
|
||||
io.bus.address := io.physical_address
|
||||
io.bus.read := true.B
|
||||
mem_access_state := MemoryAccessStates.Read
|
||||
}
|
||||
}.elsewhen(mem_access_state === MemoryAccessStates.Read) {
|
||||
io.bus.request := true.B
|
||||
io.bus.read := false.B
|
||||
io.ctrl_stall_flag := true.B
|
||||
when(io.bus.read_valid) {
|
||||
val data = io.bus.read_data
|
||||
io.wb_memory_read_data := MuxLookup(io.funct3, 0.U)(
|
||||
IndexedSeq(
|
||||
InstructionsTypeL.lb -> MuxLookup(mem_address_index, Cat(Fill(24, data(31)), data(31, 24)))(
|
||||
IndexedSeq(
|
||||
0.U -> Cat(Fill(24, data(7)), data(7, 0)),
|
||||
1.U -> Cat(Fill(24, data(15)), data(15, 8)),
|
||||
2.U -> Cat(Fill(24, data(23)), data(23, 16))
|
||||
)
|
||||
),
|
||||
InstructionsTypeL.lbu -> MuxLookup(mem_address_index, Cat(Fill(24, 0.U), data(31, 24)))(
|
||||
IndexedSeq(
|
||||
0.U -> Cat(Fill(24, 0.U), data(7, 0)),
|
||||
1.U -> Cat(Fill(24, 0.U), data(15, 8)),
|
||||
2.U -> Cat(Fill(24, 0.U), data(23, 16))
|
||||
)
|
||||
),
|
||||
InstructionsTypeL.lh -> Mux(
|
||||
mem_address_index === 0.U,
|
||||
Cat(Fill(16, data(15)), data(15, 0)),
|
||||
Cat(Fill(16, data(31)), data(31, 16))
|
||||
),
|
||||
InstructionsTypeL.lhu -> Mux(
|
||||
mem_address_index === 0.U,
|
||||
Cat(Fill(16, 0.U), data(15, 0)),
|
||||
Cat(Fill(16, 0.U), data(31, 16))
|
||||
),
|
||||
InstructionsTypeL.lw -> data
|
||||
)
|
||||
)
|
||||
on_bus_transaction_finished()
|
||||
}
|
||||
}
|
||||
}.elsewhen(io.memory_write_enable) {
|
||||
when(mem_access_state === MemoryAccessStates.Idle) {
|
||||
// Start the write transaction when there the bus is available
|
||||
io.ctrl_stall_flag := true.B
|
||||
io.bus.write_data := io.reg2_data
|
||||
io.bus.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B))
|
||||
when(io.funct3 === InstructionsTypeS.sb) {
|
||||
io.bus.write_strobe(mem_address_index) := true.B
|
||||
io.bus.write_data := io.reg2_data(Parameters.ByteBits, 0) << (mem_address_index << log2Up(Parameters
|
||||
.ByteBits).U)
|
||||
}.elsewhen(io.funct3 === InstructionsTypeS.sh) {
|
||||
when(mem_address_index === 0.U) {
|
||||
for (i <- 0 until Parameters.WordSize / 2) {
|
||||
io.bus.write_strobe(i) := true.B
|
||||
}
|
||||
io.bus.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0)
|
||||
}.otherwise {
|
||||
for (i <- Parameters.WordSize / 2 until Parameters.WordSize) {
|
||||
io.bus.write_strobe(i) := true.B
|
||||
}
|
||||
io.bus.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0) << (Parameters
|
||||
.WordSize / 2 * Parameters.ByteBits)
|
||||
}
|
||||
}.elsewhen(io.funct3 === InstructionsTypeS.sw) {
|
||||
for (i <- 0 until Parameters.WordSize) {
|
||||
io.bus.write_strobe(i) := true.B
|
||||
}
|
||||
}
|
||||
io.bus.request := true.B
|
||||
when(io.bus.granted) {
|
||||
io.bus.write := true.B
|
||||
mem_access_state := MemoryAccessStates.Write
|
||||
}
|
||||
}.elsewhen(mem_access_state === MemoryAccessStates.Write) {
|
||||
io.bus.request := true.B
|
||||
io.ctrl_stall_flag := true.B
|
||||
io.bus.write := false.B
|
||||
when(io.bus.write_valid) {
|
||||
on_bus_transaction_finished()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
io.forward_data := Mux(io.regs_write_source === RegWriteSource.CSR, io.csr_read_data, io.alu_result)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.fivestage
|
||||
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
|
||||
class PipelineRegister(width: Int = Parameters.DataBits, defaultValue: UInt = 0.U) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val write_enable = Input(Bool())
|
||||
val flush_enable = Input(Bool())
|
||||
val in = Input(UInt(width.W))
|
||||
val out = Output(UInt(width.W))
|
||||
})
|
||||
|
||||
val reg = RegInit(UInt(width.W), defaultValue)
|
||||
when(io.write_enable) {
|
||||
reg := io.in
|
||||
}.elsewhen(io.flush_enable) {
|
||||
reg := defaultValue
|
||||
}
|
||||
io.out := reg
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.fivestage
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import riscv.Parameters
|
||||
|
||||
object Registers extends Enumeration {
|
||||
type Register = Value
|
||||
val zero,
|
||||
ra, sp, gp, tp,
|
||||
t0, t1, t2, fp,
|
||||
s1,
|
||||
a0, a1, a2, a3, a4, a5, a6, a7,
|
||||
s2, s3, s4, s5, s6, s7, s8, s9, s10, s11,
|
||||
t3, t4, t5, t6 = Value
|
||||
}
|
||||
|
||||
class RegisterFile extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val write_enable = Input(Bool())
|
||||
val write_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val write_data = Input(UInt(Parameters.DataWidth))
|
||||
|
||||
val read_address1 = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val read_address2 = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val read_data1 = Output(UInt(Parameters.DataWidth))
|
||||
val read_data2 = Output(UInt(Parameters.DataWidth))
|
||||
|
||||
val debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val debug_read_data = Output(UInt(Parameters.DataWidth))
|
||||
})
|
||||
val registers = Reg(Vec(Parameters.PhysicalRegisters, UInt(Parameters.DataWidth)))
|
||||
|
||||
when(!reset.asBool) {
|
||||
when(io.write_enable && io.write_address =/= 0.U) {
|
||||
registers(io.write_address) := io.write_data
|
||||
}
|
||||
}
|
||||
|
||||
io.read_data1 := MuxCase(
|
||||
registers(io.read_address1),
|
||||
IndexedSeq(
|
||||
(io.read_address1 === 0.U) -> 0.U,
|
||||
(io.read_address1 === io.write_address && io.write_enable) -> io.write_data
|
||||
)
|
||||
)
|
||||
|
||||
io.read_data2 := MuxCase(
|
||||
registers(io.read_address2),
|
||||
IndexedSeq(
|
||||
(io.read_address2 === 0.U) -> 0.U,
|
||||
(io.read_address2 === io.write_address && io.write_enable) -> io.write_data
|
||||
)
|
||||
)
|
||||
|
||||
io.debug_read_data := MuxCase(
|
||||
registers(io.debug_read_address),
|
||||
IndexedSeq(
|
||||
(io.debug_read_address === 0.U) -> 0.U,
|
||||
(io.debug_read_address === io.write_address && io.write_enable) -> io.write_data
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright 2022 Canbin Huang
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.fivestage
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import riscv.Parameters
|
||||
|
||||
class WriteBack extends Module {
|
||||
val io = IO(new Bundle() {
|
||||
val instruction_address = Input(UInt(Parameters.AddrWidth))
|
||||
val alu_result = Input(UInt(Parameters.DataWidth))
|
||||
val memory_read_data = Input(UInt(Parameters.DataWidth))
|
||||
val regs_write_source = Input(UInt(2.W))
|
||||
val csr_read_data = Input(UInt(Parameters.DataWidth))
|
||||
|
||||
val regs_write_data = Output(UInt(Parameters.DataWidth))
|
||||
})
|
||||
io.regs_write_data := MuxLookup(io.regs_write_source, io.alu_result)(
|
||||
IndexedSeq(
|
||||
RegWriteSource.Memory -> io.memory_read_data,
|
||||
RegWriteSource.CSR -> io.csr_read_data,
|
||||
RegWriteSource.NextInstructionAddress -> (io.instruction_address + 4.U)
|
||||
)
|
||||
)
|
||||
}
|
||||
66
mini-yatcpu/src/main/scala/riscv/core/threestage/ALU.scala
Normal file
66
mini-yatcpu/src/main/scala/riscv/core/threestage/ALU.scala
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.threestage
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import riscv.Parameters
|
||||
|
||||
object ALUFunctions extends ChiselEnum {
|
||||
val zero, add, sub, sll, slt, xor, or, and, sr, sltu = Value
|
||||
}
|
||||
|
||||
class ALU extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val func = Input(ALUFunctions())
|
||||
|
||||
val op1 = Input(UInt(Parameters.DataWidth))
|
||||
val op2 = Input(UInt(Parameters.DataWidth))
|
||||
|
||||
val result = Output(UInt(Parameters.DataWidth))
|
||||
})
|
||||
|
||||
io.result := 0.U
|
||||
switch(io.func) {
|
||||
is(ALUFunctions.add) {
|
||||
io.result := io.op1 + io.op2
|
||||
}
|
||||
is(ALUFunctions.sub) {
|
||||
io.result := io.op1 - io.op2
|
||||
}
|
||||
is(ALUFunctions.sll) {
|
||||
io.result := io.op1 << io.op2(4, 0)
|
||||
}
|
||||
is(ALUFunctions.slt) {
|
||||
io.result := io.op1.asSInt < io.op2.asSInt
|
||||
}
|
||||
is(ALUFunctions.xor) {
|
||||
io.result := io.op1 ^ io.op2
|
||||
}
|
||||
is(ALUFunctions.or) {
|
||||
io.result := io.op1 | io.op2
|
||||
}
|
||||
is(ALUFunctions.and) {
|
||||
io.result := io.op1 & io.op2
|
||||
}
|
||||
is(ALUFunctions.sr) {
|
||||
io.result := io.op1 >> io.op2(4, 0)
|
||||
}
|
||||
is(ALUFunctions.sltu) {
|
||||
io.result := io.op1 < io.op2
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.threestage
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
|
||||
class ALUControl extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val opcode = Input(UInt(7.W))
|
||||
val funct3 = Input(UInt(3.W))
|
||||
val funct7 = Input(UInt(7.W))
|
||||
|
||||
val alu_funct = Output(ALUFunctions())
|
||||
})
|
||||
|
||||
io.alu_funct := ALUFunctions.zero
|
||||
|
||||
switch(io.opcode) {
|
||||
is(InstructionTypes.I) {
|
||||
io.alu_funct := MuxLookup(io.funct3, ALUFunctions.zero)(
|
||||
IndexedSeq(
|
||||
InstructionsTypeI.addi -> ALUFunctions.add,
|
||||
InstructionsTypeI.slli -> ALUFunctions.sll,
|
||||
InstructionsTypeI.slti -> ALUFunctions.slt,
|
||||
InstructionsTypeI.sltiu -> ALUFunctions.sltu,
|
||||
InstructionsTypeI.xori -> ALUFunctions.xor,
|
||||
InstructionsTypeI.ori -> ALUFunctions.or,
|
||||
InstructionsTypeI.andi -> ALUFunctions.and,
|
||||
InstructionsTypeI.sri -> ALUFunctions.sr,
|
||||
),
|
||||
)
|
||||
}
|
||||
is(InstructionTypes.RM) {
|
||||
io.alu_funct := MuxLookup(io.funct3, ALUFunctions.zero)(
|
||||
IndexedSeq(
|
||||
InstructionsTypeR.add_sub -> Mux(io.funct7(5), ALUFunctions.sub, ALUFunctions.add),
|
||||
InstructionsTypeR.sll -> ALUFunctions.sll,
|
||||
InstructionsTypeR.slt -> ALUFunctions.slt,
|
||||
InstructionsTypeR.sltu -> ALUFunctions.sltu,
|
||||
InstructionsTypeR.xor -> ALUFunctions.xor,
|
||||
InstructionsTypeR.or -> ALUFunctions.or,
|
||||
InstructionsTypeR.and -> ALUFunctions.and,
|
||||
InstructionsTypeR.sr -> ALUFunctions.sr,
|
||||
),
|
||||
)
|
||||
}
|
||||
is(Instructions.jal) {
|
||||
io.alu_funct := ALUFunctions.add
|
||||
}
|
||||
is(Instructions.jalr) {
|
||||
io.alu_funct := ALUFunctions.add
|
||||
}
|
||||
is(Instructions.lui) {
|
||||
io.alu_funct := ALUFunctions.add
|
||||
}
|
||||
is(Instructions.auipc) {
|
||||
io.alu_funct := ALUFunctions.add
|
||||
}
|
||||
}
|
||||
}
|
||||
175
mini-yatcpu/src/main/scala/riscv/core/threestage/CLINT.scala
Normal file
175
mini-yatcpu/src/main/scala/riscv/core/threestage/CLINT.scala
Normal file
@@ -0,0 +1,175 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.threestage
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import riscv.Parameters
|
||||
|
||||
object InterruptStatus {
|
||||
val None = 0x0.U(8.W)
|
||||
val Timer0 = 0x1.U(8.W)
|
||||
val Ret = 0xFF.U(8.W)
|
||||
}
|
||||
|
||||
object InterruptEntry {
|
||||
val Timer0 = 0x4.U(8.W)
|
||||
}
|
||||
|
||||
object InterruptState {
|
||||
val Idle = 0x0.U
|
||||
val SyncAssert = 0x1.U
|
||||
val AsyncAssert = 0x2.U
|
||||
val MRET = 0x3.U
|
||||
}
|
||||
|
||||
object CSRState {
|
||||
val Idle = 0x0.U
|
||||
val MSTATUS = 0x1.U
|
||||
val MEPC = 0x2.U
|
||||
val MRET = 0x3.U
|
||||
val MCAUSE = 0x4.U
|
||||
}
|
||||
|
||||
// Core Local Interrupt Controller
|
||||
class CLINT extends Module {
|
||||
val io = IO(new Bundle {
|
||||
// Interrupt signals from peripherals
|
||||
val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth))
|
||||
|
||||
// Current instruction from instruction decode
|
||||
val instruction = Input(UInt(Parameters.InstructionWidth))
|
||||
val instruction_address_id = Input(UInt(Parameters.AddrWidth))
|
||||
|
||||
val jump_flag = Input(Bool())
|
||||
val jump_address = Input(UInt(Parameters.AddrWidth))
|
||||
|
||||
val csr_mtvec = Input(UInt(Parameters.DataWidth))
|
||||
val csr_mepc = Input(UInt(Parameters.DataWidth))
|
||||
val csr_mstatus = Input(UInt(Parameters.DataWidth))
|
||||
|
||||
// Is global interrupt enabled (from MSTATUS)?
|
||||
val interrupt_enable = Input(Bool())
|
||||
|
||||
val ctrl_stall_flag = Output(Bool())
|
||||
|
||||
val csr_reg_write_enable = Output(Bool())
|
||||
val csr_reg_write_address = Output(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val csr_reg_write_data = Output(UInt(Parameters.DataWidth))
|
||||
|
||||
val ex_interrupt_handler_address = Output(UInt(Parameters.AddrWidth))
|
||||
val ex_interrupt_assert = Output(Bool())
|
||||
})
|
||||
|
||||
val interrupt_state = WireInit(0.U)
|
||||
val csr_state = RegInit(CSRState.Idle)
|
||||
val instruction_address = RegInit(UInt(Parameters.AddrWidth), 0.U)
|
||||
val cause = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||
val interrupt_assert = RegInit(Bool(), false.B)
|
||||
val interrupt_handler_address = RegInit(UInt(Parameters.AddrWidth), 0.U)
|
||||
val csr_reg_write_enable = RegInit(Bool(), false.B)
|
||||
val csr_reg_write_address = RegInit(UInt(Parameters.CSRRegisterAddrWidth), 0.U)
|
||||
val csr_reg_write_data = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||
|
||||
io.ctrl_stall_flag := interrupt_state =/= InterruptState.Idle || csr_state =/= CSRState.Idle
|
||||
|
||||
// Interrupt FSM
|
||||
when(io.instruction === InstructionsEnv.ecall || io.instruction === InstructionsEnv.ebreak) {
|
||||
interrupt_state := InterruptState.SyncAssert
|
||||
}.elsewhen(io.interrupt_flag =/= InterruptStatus.None && io.interrupt_enable) {
|
||||
interrupt_state := InterruptState.AsyncAssert
|
||||
}.elsewhen(io.instruction === InstructionsRet.mret) {
|
||||
interrupt_state := InterruptState.MRET
|
||||
}.otherwise {
|
||||
interrupt_state := InterruptState.Idle
|
||||
}
|
||||
|
||||
// CSR FSM
|
||||
when(csr_state === CSRState.Idle) {
|
||||
when(interrupt_state === InterruptState.SyncAssert) {
|
||||
// Synchronous Interrupt
|
||||
csr_state := CSRState.MEPC
|
||||
instruction_address := Mux(
|
||||
io.jump_flag,
|
||||
io.jump_address - 4.U,
|
||||
io.instruction_address_id
|
||||
)
|
||||
|
||||
cause := MuxLookup(io.instruction, 10.U)(
|
||||
IndexedSeq(
|
||||
InstructionsEnv.ecall -> 11.U,
|
||||
InstructionsEnv.ebreak -> 3.U,
|
||||
)
|
||||
)
|
||||
}.elsewhen(interrupt_state === InterruptState.AsyncAssert) {
|
||||
// Asynchronous Interrupt
|
||||
cause := 0x8000000BL.U
|
||||
when(io.interrupt_flag(0)) {
|
||||
cause := 0x80000007L.U
|
||||
}
|
||||
csr_state := CSRState.MEPC
|
||||
instruction_address := Mux(
|
||||
io.jump_flag,
|
||||
io.jump_address,
|
||||
io.instruction_address_id,
|
||||
)
|
||||
}.elsewhen(interrupt_state === InterruptState.MRET) {
|
||||
// Interrupt Return
|
||||
csr_state := CSRState.MRET
|
||||
}
|
||||
}.elsewhen(csr_state === CSRState.MEPC) {
|
||||
csr_state := CSRState.MSTATUS
|
||||
}.elsewhen(csr_state === CSRState.MSTATUS) {
|
||||
csr_state := CSRState.MCAUSE
|
||||
}.elsewhen(csr_state === CSRState.MCAUSE) {
|
||||
csr_state := CSRState.Idle
|
||||
}.elsewhen(csr_state === CSRState.MRET) {
|
||||
csr_state := CSRState.Idle
|
||||
}.otherwise {
|
||||
csr_state := CSRState.Idle
|
||||
}
|
||||
|
||||
csr_reg_write_enable := csr_state =/= CSRState.Idle
|
||||
csr_reg_write_address := Cat(Fill(20, 0.U(1.W)), MuxLookup(csr_state, 0.U(Parameters.CSRRegisterAddrWidth))(
|
||||
IndexedSeq(
|
||||
CSRState.MEPC -> CSRRegister.MEPC,
|
||||
CSRState.MCAUSE -> CSRRegister.MCAUSE,
|
||||
CSRState.MSTATUS -> CSRRegister.MSTATUS,
|
||||
CSRState.MRET -> CSRRegister.MSTATUS,
|
||||
)
|
||||
))
|
||||
csr_reg_write_data := MuxLookup(csr_state, 0.U(Parameters.DataWidth))(
|
||||
IndexedSeq(
|
||||
CSRState.MEPC -> instruction_address,
|
||||
CSRState.MCAUSE -> cause,
|
||||
CSRState.MSTATUS -> Cat(io.csr_mstatus(31, 4), 0.U(1.W), io.csr_mstatus(2, 0)),
|
||||
CSRState.MRET -> Cat(io.csr_mstatus(31, 4), io.csr_mstatus(7), io.csr_mstatus(2, 0)),
|
||||
)
|
||||
)
|
||||
io.csr_reg_write_enable := csr_reg_write_enable
|
||||
io.csr_reg_write_address := csr_reg_write_address
|
||||
io.csr_reg_write_data := csr_reg_write_data
|
||||
|
||||
interrupt_assert := csr_state === CSRState.MCAUSE || csr_state === CSRState.MRET
|
||||
interrupt_handler_address := MuxLookup(csr_state, 0.U(Parameters.AddrWidth))(
|
||||
IndexedSeq(
|
||||
CSRState.MCAUSE -> io.csr_mtvec,
|
||||
CSRState.MRET -> io.csr_mepc,
|
||||
)
|
||||
)
|
||||
|
||||
io.ex_interrupt_assert := interrupt_assert
|
||||
io.ex_interrupt_handler_address := interrupt_handler_address
|
||||
}
|
||||
167
mini-yatcpu/src/main/scala/riscv/core/threestage/CPU.scala
Normal file
167
mini-yatcpu/src/main/scala/riscv/core/threestage/CPU.scala
Normal file
@@ -0,0 +1,167 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.threestage
|
||||
|
||||
import bus.AXI4LiteMaster
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
import riscv.core.CPUBundle
|
||||
|
||||
class CPU extends Module {
|
||||
val io = IO(new CPUBundle)
|
||||
|
||||
val ctrl = Module(new Control)
|
||||
val regs = Module(new RegisterFile)
|
||||
val inst_fetch = Module(new InstructionFetch)
|
||||
val if2id = Module(new IF2ID)
|
||||
val id = Module(new InstructionDecode)
|
||||
val id2ex = Module(new ID2EX)
|
||||
val ex = Module(new Execute)
|
||||
val clint = Module(new CLINT)
|
||||
val csr_regs = Module(new CSR)
|
||||
val axi4_master = Module(new AXI4LiteMaster(Parameters.AddrBits, Parameters.DataBits))
|
||||
|
||||
axi4_master.io.channels <> io.axi4_channels
|
||||
io.debug(0) := ex.io.reg1_data
|
||||
io.debug(1) := ex.io.reg2_data
|
||||
io.debug(2) := ex.io.instruction_address
|
||||
io.debug(3) := ex.io.instruction
|
||||
io.debug(4) := ex.io.ctrl_jump_flag
|
||||
io.debug(5) := ex.io.ctrl_jump_address
|
||||
io.bus_busy := axi4_master.io.bundle.busy
|
||||
|
||||
// The EX module takes precedence over IF (but let the previous fetch finish)
|
||||
val ex_granted = RegInit(false.B)
|
||||
when(ex_granted) {
|
||||
inst_fetch.io.instruction_valid := false.B
|
||||
io.bus_address := ex.io.bus.address
|
||||
axi4_master.io.bundle.read := ex.io.bus.read
|
||||
axi4_master.io.bundle.address := ex.io.bus.address
|
||||
axi4_master.io.bundle.write := ex.io.bus.write
|
||||
axi4_master.io.bundle.write_data := ex.io.bus.write_data
|
||||
axi4_master.io.bundle.write_strobe := ex.io.bus.write_strobe
|
||||
when(!ex.io.bus.request) {
|
||||
ex_granted := false.B
|
||||
}
|
||||
}.otherwise {
|
||||
// Default to fetch instructions from main memory
|
||||
ex_granted := false.B
|
||||
axi4_master.io.bundle.read := !axi4_master.io.bundle.busy && !axi4_master.io.bundle.read_valid && !ex.io.bus.request
|
||||
axi4_master.io.bundle.address := inst_fetch.io.bus_address
|
||||
io.bus_address := inst_fetch.io.bus_address
|
||||
axi4_master.io.bundle.write := false.B
|
||||
axi4_master.io.bundle.write_data := 0.U
|
||||
axi4_master.io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B))
|
||||
}
|
||||
|
||||
when(ex.io.bus.request) {
|
||||
when(!axi4_master.io.bundle.busy && !axi4_master.io.bundle.read_valid) {
|
||||
ex_granted := true.B
|
||||
}
|
||||
}
|
||||
|
||||
inst_fetch.io.instruction_valid := io.instruction_valid && axi4_master.io.bundle.read_valid && !ex_granted
|
||||
inst_fetch.io.bus_data := axi4_master.io.bundle.read_data
|
||||
|
||||
ex.io.bus.read_data := axi4_master.io.bundle.read_data
|
||||
ex.io.bus.read_valid := axi4_master.io.bundle.read_valid
|
||||
ex.io.bus.write_valid := axi4_master.io.bundle.write_valid
|
||||
ex.io.bus.busy := axi4_master.io.bundle.busy
|
||||
ex.io.bus.granted := ex_granted
|
||||
|
||||
ctrl.io.jump_flag := ex.io.ctrl_jump_flag
|
||||
ctrl.io.jump_address := ex.io.ctrl_jump_address
|
||||
ctrl.io.stall_flag_if := inst_fetch.io.ctrl_stall_flag
|
||||
ctrl.io.stall_flag_ex := ex.io.ctrl_stall_flag
|
||||
ctrl.io.stall_flag_id := id.io.ctrl_stall_flag
|
||||
ctrl.io.stall_flag_clint := clint.io.ctrl_stall_flag
|
||||
ctrl.io.stall_flag_bus := io.stall_flag_bus
|
||||
|
||||
regs.io.write_enable := ex.io.regs_write_enable
|
||||
regs.io.write_address := ex.io.regs_write_address
|
||||
regs.io.write_data := ex.io.regs_write_data
|
||||
regs.io.read_address1 := id.io.regs_reg1_read_address
|
||||
regs.io.read_address2 := id.io.regs_reg2_read_address
|
||||
|
||||
regs.io.debug_read_address := io.debug_read_address
|
||||
io.debug_read_data := regs.io.debug_read_data
|
||||
|
||||
inst_fetch.io.jump_flag_ctrl := ctrl.io.pc_jump_flag
|
||||
inst_fetch.io.jump_address_ctrl := ctrl.io.pc_jump_address
|
||||
inst_fetch.io.stall_flag_ctrl := ctrl.io.output_stall_flag
|
||||
|
||||
if2id.io.instruction := inst_fetch.io.id_instruction
|
||||
if2id.io.instruction_address := inst_fetch.io.id_instruction_address
|
||||
if2id.io.stall_flag := ctrl.io.output_stall_flag
|
||||
if2id.io.jump_flag := ctrl.io.pc_jump_flag
|
||||
if2id.io.interrupt_flag := io.interrupt_flag
|
||||
|
||||
id.io.reg1_data := regs.io.read_data1
|
||||
id.io.reg2_data := regs.io.read_data2
|
||||
id.io.instruction := if2id.io.output_instruction
|
||||
id.io.instruction_address := if2id.io.output_instruction_address
|
||||
id.io.csr_read_data := csr_regs.io.id_reg_data
|
||||
|
||||
id2ex.io.instruction := id.io.ex_instruction
|
||||
id2ex.io.instruction_address := id.io.ex_instruction_address
|
||||
id2ex.io.csr_read_data := id.io.ex_csr_read_data
|
||||
id2ex.io.csr_write_enable := id.io.ex_csr_write_enable
|
||||
id2ex.io.csr_write_address := id.io.ex_csr_write_address
|
||||
id2ex.io.op1 := id.io.ex_op1
|
||||
id2ex.io.op2 := id.io.ex_op2
|
||||
id2ex.io.op1_jump := id.io.ex_op1_jump
|
||||
id2ex.io.op2_jump := id.io.ex_op2_jump
|
||||
id2ex.io.reg1_data := id.io.ex_reg1_data
|
||||
id2ex.io.reg2_data := id.io.ex_reg2_data
|
||||
id2ex.io.regs_write_enable := id.io.ex_reg_write_enable
|
||||
id2ex.io.regs_write_address := id.io.ex_reg_write_address
|
||||
id2ex.io.stall_flag := ctrl.io.output_stall_flag
|
||||
id2ex.io.jump_flag := ctrl.io.pc_jump_flag
|
||||
|
||||
ex.io.instruction := id2ex.io.output_instruction
|
||||
ex.io.instruction_address := id2ex.io.output_instruction_address
|
||||
ex.io.csr_reg_data_id := id2ex.io.output_csr_read_data
|
||||
ex.io.csr_reg_write_enable_id := id2ex.io.output_csr_write_enable
|
||||
ex.io.csr_reg_write_address_id := id2ex.io.output_csr_write_address
|
||||
ex.io.op1 := id2ex.io.output_op1
|
||||
ex.io.op2 := id2ex.io.output_op2
|
||||
ex.io.op1_jump := id2ex.io.output_op1_jump
|
||||
ex.io.op2_jump := id2ex.io.output_op2_jump
|
||||
ex.io.reg1_data := id2ex.io.output_reg1_data
|
||||
ex.io.reg2_data := id2ex.io.output_reg2_data
|
||||
ex.io.regs_write_enable_id := id2ex.io.output_regs_write_enable
|
||||
ex.io.regs_write_address_id := id2ex.io.output_regs_write_address
|
||||
ex.io.interrupt_assert := clint.io.ex_interrupt_assert
|
||||
ex.io.interrupt_handler_address := clint.io.ex_interrupt_handler_address
|
||||
|
||||
clint.io.instruction := id.io.ex_instruction
|
||||
clint.io.instruction_address_id := id.io.instruction_address
|
||||
clint.io.jump_flag := ex.io.ctrl_jump_flag
|
||||
clint.io.jump_address := ex.io.ctrl_jump_address
|
||||
clint.io.csr_mepc := csr_regs.io.clint_csr_mepc
|
||||
clint.io.csr_mtvec := csr_regs.io.clint_csr_mtvec
|
||||
clint.io.csr_mstatus := csr_regs.io.clint_csr_mstatus
|
||||
clint.io.interrupt_enable := csr_regs.io.interrupt_enable
|
||||
clint.io.interrupt_flag := if2id.io.output_interrupt_flag
|
||||
|
||||
csr_regs.io.reg_write_enable_ex := ex.io.csr_reg_write_enable
|
||||
csr_regs.io.reg_write_address_ex := ex.io.csr_reg_write_address
|
||||
csr_regs.io.reg_write_data_ex := ex.io.csr_reg_write_data
|
||||
csr_regs.io.reg_read_address_id := id.io.csr_read_address
|
||||
csr_regs.io.reg_write_enable_clint := clint.io.csr_reg_write_enable
|
||||
csr_regs.io.reg_write_address_clint := clint.io.csr_reg_write_address
|
||||
csr_regs.io.reg_write_data_clint := clint.io.csr_reg_write_data
|
||||
csr_regs.io.reg_read_address_clint := 0.U
|
||||
}
|
||||
122
mini-yatcpu/src/main/scala/riscv/core/threestage/CSR.scala
Normal file
122
mini-yatcpu/src/main/scala/riscv/core/threestage/CSR.scala
Normal file
@@ -0,0 +1,122 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.threestage
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import riscv.Parameters
|
||||
|
||||
|
||||
object CSRRegister {
|
||||
// Refer to Spec. Vol.II Page 8-10
|
||||
val CycleL = 0xc00.U(Parameters.CSRRegisterAddrWidth)
|
||||
val CycleH = 0xc80.U(Parameters.CSRRegisterAddrWidth)
|
||||
val MTVEC = 0x305.U(Parameters.CSRRegisterAddrWidth)
|
||||
val MCAUSE = 0x342.U(Parameters.CSRRegisterAddrWidth)
|
||||
val MEPC = 0x341.U(Parameters.CSRRegisterAddrWidth)
|
||||
val MIE = 0x304.U(Parameters.CSRRegisterAddrWidth)
|
||||
val MSTATUS = 0x300.U(Parameters.CSRRegisterAddrWidth)
|
||||
val MSCRATCH = 0x340.U(Parameters.CSRRegisterAddrWidth)
|
||||
}
|
||||
|
||||
class CSR extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val reg_write_enable_ex = Input(Bool())
|
||||
val reg_read_address_id = Input(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val reg_write_address_ex = Input(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val reg_write_data_ex = Input(UInt(Parameters.DataWidth))
|
||||
|
||||
val reg_write_enable_clint = Input(Bool())
|
||||
val reg_read_address_clint = Input(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val reg_write_address_clint = Input(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val reg_write_data_clint = Input(UInt(Parameters.DataWidth))
|
||||
|
||||
val interrupt_enable = Output(Bool())
|
||||
|
||||
val id_reg_data = Output(UInt(Parameters.DataWidth))
|
||||
|
||||
val clint_reg_data = Output(UInt(Parameters.DataWidth))
|
||||
val clint_csr_mtvec = Output(UInt(Parameters.DataWidth))
|
||||
val clint_csr_mepc = Output(UInt(Parameters.DataWidth))
|
||||
val clint_csr_mstatus = Output(UInt(Parameters.DataWidth))
|
||||
})
|
||||
|
||||
|
||||
val cycles = RegInit(UInt(64.W), 0.U)
|
||||
val mtvec = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||
val mcause = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||
val mepc = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||
val mie = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||
val mstatus = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||
val mscratch = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||
|
||||
cycles := cycles + 1.U
|
||||
io.clint_csr_mtvec := mtvec
|
||||
io.clint_csr_mepc := mepc
|
||||
io.clint_csr_mstatus := mstatus
|
||||
io.interrupt_enable := mstatus(3) === 1.U
|
||||
|
||||
val reg_write_address = Wire(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val reg_write_data = Wire(UInt(Parameters.DataWidth))
|
||||
reg_write_address := 0.U
|
||||
reg_write_data := 0.U
|
||||
|
||||
val reg_read_address = Wire(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val reg_read_data = Wire(UInt(Parameters.DataWidth))
|
||||
reg_read_address := 0.U
|
||||
reg_read_data := 0.U
|
||||
|
||||
when(io.reg_write_enable_ex) {
|
||||
reg_write_address := io.reg_write_address_ex(11, 0)
|
||||
reg_write_data := io.reg_write_data_ex
|
||||
}.elsewhen(io.reg_write_enable_clint) {
|
||||
reg_write_address := io.reg_write_address_clint(11, 0)
|
||||
reg_write_data := io.reg_write_data_clint
|
||||
}
|
||||
|
||||
when(reg_write_address === CSRRegister.MTVEC) {
|
||||
mtvec := reg_write_data
|
||||
}.elsewhen(reg_write_address === CSRRegister.MCAUSE) {
|
||||
mcause := reg_write_data
|
||||
}.elsewhen(reg_write_address === CSRRegister.MEPC) {
|
||||
mepc := reg_write_data
|
||||
}.elsewhen(reg_write_address === CSRRegister.MIE) {
|
||||
mie := reg_write_data
|
||||
}.elsewhen(reg_write_address === CSRRegister.MSTATUS) {
|
||||
mstatus := reg_write_data
|
||||
}.elsewhen(reg_write_address === CSRRegister.MSCRATCH) {
|
||||
mscratch := reg_write_data
|
||||
}
|
||||
|
||||
val regLUT =
|
||||
IndexedSeq(
|
||||
CSRRegister.CycleL -> cycles(31, 0),
|
||||
CSRRegister.CycleH -> cycles(63, 32),
|
||||
CSRRegister.MTVEC -> mtvec,
|
||||
CSRRegister.MCAUSE -> mcause,
|
||||
CSRRegister.MEPC -> mepc,
|
||||
CSRRegister.MIE -> mie,
|
||||
CSRRegister.MSTATUS -> mstatus,
|
||||
CSRRegister.MSCRATCH -> mscratch,
|
||||
)
|
||||
|
||||
io.id_reg_data := MuxLookup(io.reg_read_address_id, 0.U)(
|
||||
regLUT
|
||||
)
|
||||
|
||||
io.clint_reg_data := MuxLookup(io.reg_read_address_clint, 0.U)(
|
||||
regLUT
|
||||
)
|
||||
}
|
||||
23
mini-yatcpu/src/main/scala/riscv/core/threestage/Cache.scala
Normal file
23
mini-yatcpu/src/main/scala/riscv/core/threestage/Cache.scala
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.threestage
|
||||
|
||||
import chisel3._
|
||||
|
||||
class Cache(cacheLineBytes: Int, associativity: Int, cacheLines: Int) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.threestage
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import riscv.Parameters
|
||||
|
||||
object StallStates {
|
||||
val None = 0.U
|
||||
val PC = 1.U
|
||||
val IF = 2.U
|
||||
val ID = 3.U
|
||||
}
|
||||
|
||||
class Control extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val jump_flag = Input(Bool())
|
||||
val stall_flag_if = Input(Bool())
|
||||
val stall_flag_id = Input(Bool())
|
||||
val stall_flag_ex = Input(Bool())
|
||||
val stall_flag_clint = Input(Bool())
|
||||
val stall_flag_bus = Input(Bool())
|
||||
val jump_address = Input(UInt(Parameters.AddrWidth))
|
||||
|
||||
val output_stall_flag = Output(UInt(Parameters.StallStateWidth))
|
||||
|
||||
val pc_jump_flag = Output(Bool())
|
||||
val pc_jump_address = Output(UInt(Parameters.AddrWidth))
|
||||
})
|
||||
|
||||
io.pc_jump_flag := io.jump_flag
|
||||
io.pc_jump_address := io.jump_address
|
||||
|
||||
io.output_stall_flag := MuxCase(
|
||||
StallStates.None,
|
||||
IndexedSeq(
|
||||
(io.jump_flag || io.stall_flag_ex || io.stall_flag_clint) -> StallStates.ID,
|
||||
io.stall_flag_id -> StallStates.IF,
|
||||
(io.stall_flag_bus || io.stall_flag_if) -> StallStates.PC,
|
||||
)
|
||||
)
|
||||
}
|
||||
310
mini-yatcpu/src/main/scala/riscv/core/threestage/Execute.scala
Normal file
310
mini-yatcpu/src/main/scala/riscv/core/threestage/Execute.scala
Normal file
@@ -0,0 +1,310 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.threestage
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import riscv.Parameters
|
||||
import riscv.core.BusBundle
|
||||
|
||||
object MemoryAccessStates extends ChiselEnum {
|
||||
val Idle, Read, Write, ReadWrite = Value
|
||||
}
|
||||
|
||||
class Execute extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val instruction = Input(UInt(Parameters.InstructionWidth))
|
||||
val instruction_address = Input(UInt(Parameters.AddrWidth))
|
||||
val interrupt_assert = Input(Bool())
|
||||
val interrupt_handler_address = Input(UInt(Parameters.AddrWidth))
|
||||
val regs_write_enable_id = Input(Bool())
|
||||
val regs_write_address_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val csr_reg_write_enable_id = Input(Bool())
|
||||
val csr_reg_write_address_id = Input(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val csr_reg_data_id = Input(UInt(Parameters.DataWidth))
|
||||
val reg1_data = Input(UInt(Parameters.DataWidth))
|
||||
val reg2_data = Input(UInt(Parameters.DataWidth))
|
||||
val op1 = Input(UInt(Parameters.DataWidth))
|
||||
val op2 = Input(UInt(Parameters.DataWidth))
|
||||
val op1_jump = Input(UInt(Parameters.DataWidth))
|
||||
val op2_jump = Input(UInt(Parameters.DataWidth))
|
||||
|
||||
val bus = new BusBundle
|
||||
|
||||
val regs_write_enable = Output(Bool())
|
||||
val regs_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val regs_write_data = Output(UInt(Parameters.DataWidth))
|
||||
|
||||
val ctrl_stall_flag = Output(Bool())
|
||||
val ctrl_jump_flag = Output(Bool())
|
||||
val ctrl_jump_address = Output(UInt(Parameters.AddrWidth))
|
||||
|
||||
val csr_reg_write_enable = Output(Bool())
|
||||
val csr_reg_write_address = Output(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val csr_reg_write_data = Output(UInt(Parameters.DataWidth))
|
||||
})
|
||||
|
||||
val opcode = io.instruction(6, 0)
|
||||
val funct3 = io.instruction(14, 12)
|
||||
val funct7 = io.instruction(31, 25)
|
||||
val rd = io.instruction(11, 7)
|
||||
val uimm = io.instruction(19, 15)
|
||||
|
||||
val alu = Module(new ALU)
|
||||
val alu_ctrl = Module(new ALUControl)
|
||||
|
||||
alu_ctrl.io.opcode := opcode
|
||||
alu_ctrl.io.funct3 := funct3
|
||||
alu_ctrl.io.funct7 := funct7
|
||||
alu.io.func := alu_ctrl.io.alu_funct
|
||||
alu.io.op1 := io.op1
|
||||
alu.io.op2 := io.op2
|
||||
|
||||
|
||||
val mem_read_address_index = (io.op1 + io.op2)(log2Up(Parameters.WordSize) - 1, 0).asUInt
|
||||
val mem_write_address_index = (io.op1 + io.op2)(log2Up(Parameters.WordSize) - 1, 0).asUInt
|
||||
val mem_access_state = RegInit(MemoryAccessStates.Idle)
|
||||
val pending_interrupt = RegInit(false.B)
|
||||
val pending_interrupt_handler_address = RegInit(Parameters.EntryAddress)
|
||||
|
||||
val jump_flag = Wire(Bool())
|
||||
val jump_address = Wire(UInt(Parameters.AddrWidth))
|
||||
|
||||
io.ctrl_jump_flag := jump_flag || io.interrupt_assert
|
||||
io.ctrl_jump_address := Mux(io.interrupt_assert, io.interrupt_handler_address, jump_address)
|
||||
|
||||
io.bus.read := false.B
|
||||
io.bus.address := 0.U
|
||||
io.bus.write_data := 0.U
|
||||
io.bus.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B))
|
||||
io.bus.write := false.B
|
||||
io.regs_write_enable := io.regs_write_enable_id && !io.interrupt_assert
|
||||
io.regs_write_address := io.regs_write_address_id
|
||||
io.regs_write_data := 0.U
|
||||
io.csr_reg_write_enable := io.csr_reg_write_enable_id && !io.interrupt_assert
|
||||
io.csr_reg_write_address := io.csr_reg_write_address_id
|
||||
io.csr_reg_write_data := 0.U
|
||||
io.bus.request := false.B
|
||||
|
||||
def disable_control() = {
|
||||
disable_stall()
|
||||
disable_jump()
|
||||
}
|
||||
|
||||
def disable_stall() = {
|
||||
io.ctrl_stall_flag := false.B
|
||||
}
|
||||
|
||||
def disable_jump() = {
|
||||
jump_address := 0.U
|
||||
jump_flag := false.B
|
||||
}
|
||||
|
||||
def check_interrupt_during_bus_transaction() = {
|
||||
// Store the interrupt and process later
|
||||
when(io.interrupt_assert) {
|
||||
pending_interrupt := true.B
|
||||
pending_interrupt_handler_address := io.interrupt_handler_address
|
||||
io.ctrl_jump_flag := false.B
|
||||
}
|
||||
}
|
||||
|
||||
def on_bus_transaction_finished() = {
|
||||
mem_access_state := MemoryAccessStates.Idle
|
||||
io.ctrl_stall_flag := false.B
|
||||
when(pending_interrupt) {
|
||||
pending_interrupt := false.B
|
||||
io.ctrl_jump_flag := true.B
|
||||
io.ctrl_jump_address := pending_interrupt_handler_address
|
||||
}
|
||||
}
|
||||
|
||||
when(opcode === InstructionTypes.I) {
|
||||
disable_control()
|
||||
val mask = (0xFFFFFFFFL.U >> io.instruction(24, 20)).asUInt
|
||||
io.regs_write_data := alu.io.result
|
||||
when(funct3 === InstructionsTypeI.sri) {
|
||||
when(funct7(5).asBool) {
|
||||
io.regs_write_data := alu.io.result & mask |
|
||||
(Fill(32, io.op1(31)) & (~mask).asUInt).asUInt
|
||||
}
|
||||
}
|
||||
}.elsewhen(opcode === InstructionTypes.RM) {
|
||||
disable_control()
|
||||
// TODO(howard): support mul and div
|
||||
when(funct7 === 0.U || funct7 === 0x20.U) {
|
||||
val mask = (0xFFFFFFFFL.U >> io.reg2_data(4, 0)).asUInt
|
||||
io.regs_write_data := alu.io.result
|
||||
when(funct3 === InstructionsTypeR.sr) {
|
||||
when(funct7(5).asBool) {
|
||||
io.regs_write_data := alu.io.result & mask |
|
||||
(Fill(32, io.op1(31)) & (~mask).asUInt).asUInt
|
||||
}
|
||||
}
|
||||
}
|
||||
}.elsewhen(opcode === InstructionTypes.L) {
|
||||
disable_control()
|
||||
|
||||
when(mem_access_state === MemoryAccessStates.Idle) {
|
||||
// Start the read transaction when there is no interrupt asserted
|
||||
// and the bus is available
|
||||
when(!io.interrupt_assert) {
|
||||
io.ctrl_stall_flag := true.B
|
||||
io.regs_write_enable := false.B
|
||||
io.bus.read := true.B
|
||||
io.bus.address := io.op1 + io.op2
|
||||
io.bus.request := true.B
|
||||
when(io.bus.granted) {
|
||||
mem_access_state := MemoryAccessStates.Read
|
||||
}
|
||||
}
|
||||
}.elsewhen(mem_access_state === MemoryAccessStates.Read) {
|
||||
check_interrupt_during_bus_transaction()
|
||||
io.bus.request := true.B
|
||||
io.bus.read := false.B
|
||||
io.ctrl_stall_flag := true.B
|
||||
io.bus.address := io.op1 + io.op2
|
||||
when(io.bus.read_valid) {
|
||||
io.regs_write_enable := true.B
|
||||
val data = io.bus.read_data
|
||||
io.regs_write_data := MuxLookup(funct3, 0.U)(
|
||||
IndexedSeq(
|
||||
InstructionsTypeL.lb -> MuxLookup(
|
||||
mem_read_address_index,
|
||||
Cat(Fill(24, data(31)), data(31, 24)))(
|
||||
IndexedSeq(
|
||||
0.U -> Cat(Fill(24, data(7)), data(7, 0)),
|
||||
1.U -> Cat(Fill(24, data(15)), data(15, 8)),
|
||||
2.U -> Cat(Fill(24, data(23)), data(23, 16))
|
||||
)
|
||||
),
|
||||
InstructionsTypeL.lbu -> MuxLookup(
|
||||
mem_read_address_index,
|
||||
Cat(Fill(24, 0.U), data(31, 24)))(
|
||||
IndexedSeq(
|
||||
0.U -> Cat(Fill(24, 0.U), data(7, 0)),
|
||||
1.U -> Cat(Fill(24, 0.U), data(15, 8)),
|
||||
2.U -> Cat(Fill(24, 0.U), data(23, 16))
|
||||
)
|
||||
),
|
||||
InstructionsTypeL.lh -> Mux(
|
||||
mem_read_address_index === 0.U,
|
||||
Cat(Fill(16, data(15)), data(15, 0)),
|
||||
Cat(Fill(16, data(31)), data(31, 16))
|
||||
),
|
||||
InstructionsTypeL.lhu -> Mux(
|
||||
mem_read_address_index === 0.U,
|
||||
Cat(Fill(16, 0.U), data(15, 0)),
|
||||
Cat(Fill(16, 0.U), data(31, 16))
|
||||
),
|
||||
InstructionsTypeL.lw -> data
|
||||
)
|
||||
)
|
||||
on_bus_transaction_finished()
|
||||
}
|
||||
}
|
||||
}.elsewhen(opcode === InstructionTypes.S) {
|
||||
disable_control()
|
||||
|
||||
when(mem_access_state === MemoryAccessStates.Idle) {
|
||||
// Start the write transaction when there is no interrupt asserted
|
||||
// and the bus is available
|
||||
when(!io.interrupt_assert) {
|
||||
io.ctrl_stall_flag := true.B
|
||||
io.bus.address := io.op1 + io.op2
|
||||
io.bus.write_data := io.reg2_data
|
||||
io.bus.write := true.B
|
||||
io.bus.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B))
|
||||
when(funct3 === InstructionsTypeS.sb) {
|
||||
io.bus.write_strobe(mem_write_address_index) := true.B
|
||||
io.bus.write_data := io.reg2_data(Parameters.ByteBits, 0) << (mem_write_address_index << log2Up(Parameters
|
||||
.ByteBits).U)
|
||||
}.elsewhen(funct3 === InstructionsTypeS.sh) {
|
||||
when(mem_write_address_index === 0.U) {
|
||||
for (i <- 0 until Parameters.WordSize / 2) {
|
||||
io.bus.write_strobe(i) := true.B
|
||||
}
|
||||
io.bus.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0)
|
||||
}.otherwise {
|
||||
for (i <- Parameters.WordSize / 2 until Parameters.WordSize) {
|
||||
io.bus.write_strobe(i) := true.B
|
||||
}
|
||||
io.bus.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0) << (Parameters
|
||||
.WordSize / 2 * Parameters.ByteBits)
|
||||
}
|
||||
}.elsewhen(funct3 === InstructionsTypeS.sw) {
|
||||
for (i <- 0 until Parameters.WordSize) {
|
||||
io.bus.write_strobe(i) := true.B
|
||||
}
|
||||
}
|
||||
io.bus.request := true.B
|
||||
when(io.bus.granted) {
|
||||
mem_access_state := MemoryAccessStates.Write
|
||||
}
|
||||
}
|
||||
}.elsewhen(mem_access_state === MemoryAccessStates.Write) {
|
||||
check_interrupt_during_bus_transaction()
|
||||
io.bus.request := true.B
|
||||
io.ctrl_stall_flag := true.B
|
||||
io.bus.write := false.B
|
||||
io.bus.address := io.op1 + io.op2
|
||||
when(io.bus.write_valid) {
|
||||
on_bus_transaction_finished()
|
||||
}
|
||||
}
|
||||
}.elsewhen(opcode === InstructionTypes.B) {
|
||||
disable_control()
|
||||
jump_flag := MuxLookup(funct3, 0.U)(
|
||||
IndexedSeq(
|
||||
InstructionsTypeB.beq -> (io.op1 === io.op2),
|
||||
InstructionsTypeB.bne -> (io.op1 =/= io.op2),
|
||||
InstructionsTypeB.bltu -> (io.op1 < io.op2),
|
||||
InstructionsTypeB.bgeu -> (io.op1 >= io.op2),
|
||||
InstructionsTypeB.blt -> (io.op1.asSInt < io.op2.asSInt),
|
||||
InstructionsTypeB.bge -> (io.op1.asSInt >= io.op2.asSInt)
|
||||
)
|
||||
)
|
||||
jump_address := Fill(32, io.ctrl_jump_flag) & (io.op1_jump + io.op2_jump)
|
||||
}.elsewhen(opcode === Instructions.jal || opcode === Instructions.jalr) {
|
||||
disable_stall()
|
||||
jump_flag := true.B
|
||||
jump_address := io.op1_jump + io.op2_jump
|
||||
io.regs_write_data := io.op1 + io.op2
|
||||
}.elsewhen(opcode === Instructions.lui || opcode === Instructions.auipc) {
|
||||
disable_control()
|
||||
io.regs_write_data := io.op1 + io.op2
|
||||
}.elsewhen(opcode === Instructions.csr) {
|
||||
disable_control()
|
||||
io.csr_reg_write_data := MuxLookup(funct3, 0.U)(IndexedSeq(
|
||||
InstructionsTypeCSR.csrrw -> io.reg1_data,
|
||||
InstructionsTypeCSR.csrrc -> io.csr_reg_data_id.&((~io.reg1_data).asUInt),
|
||||
InstructionsTypeCSR.csrrs -> io.csr_reg_data_id.|(io.reg1_data),
|
||||
InstructionsTypeCSR.csrrwi -> Cat(0.U(27.W), uimm),
|
||||
InstructionsTypeCSR.csrrci -> io.csr_reg_data_id.&((~Cat(0.U(27.W), uimm)).asUInt),
|
||||
InstructionsTypeCSR.csrrsi -> io.csr_reg_data_id.|(Cat(0.U(27.W), uimm)),
|
||||
))
|
||||
io.regs_write_data := MuxLookup(funct3, 0.U)(IndexedSeq(
|
||||
InstructionsTypeCSR.csrrw -> io.csr_reg_data_id,
|
||||
InstructionsTypeCSR.csrrc -> io.csr_reg_data_id,
|
||||
InstructionsTypeCSR.csrrs -> io.csr_reg_data_id,
|
||||
InstructionsTypeCSR.csrrwi -> io.csr_reg_data_id,
|
||||
InstructionsTypeCSR.csrrci -> io.csr_reg_data_id,
|
||||
InstructionsTypeCSR.csrrsi -> io.csr_reg_data_id,
|
||||
))
|
||||
}.otherwise {
|
||||
disable_control()
|
||||
io.regs_write_data := 0.U
|
||||
}
|
||||
}
|
||||
132
mini-yatcpu/src/main/scala/riscv/core/threestage/ID2EX.scala
Normal file
132
mini-yatcpu/src/main/scala/riscv/core/threestage/ID2EX.scala
Normal file
@@ -0,0 +1,132 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.threestage
|
||||
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
|
||||
class ID2EX extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val instruction = Input(UInt(Parameters.InstructionWidth))
|
||||
val instruction_address = Input(UInt(Parameters.AddrWidth))
|
||||
val regs_write_enable = Input(Bool())
|
||||
val regs_write_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val reg1_data = Input(UInt(Parameters.DataWidth))
|
||||
val reg2_data = Input(UInt(Parameters.DataWidth))
|
||||
val op1 = Input(UInt(Parameters.DataWidth))
|
||||
val op2 = Input(UInt(Parameters.DataWidth))
|
||||
val op1_jump = Input(UInt(Parameters.DataWidth))
|
||||
val op2_jump = Input(UInt(Parameters.DataWidth))
|
||||
val csr_write_enable = Input(Bool())
|
||||
val csr_write_address = Input(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val csr_read_data = Input(UInt(Parameters.DataWidth))
|
||||
val stall_flag = Input(UInt(Parameters.StallStateWidth))
|
||||
val jump_flag = Input(Bool())
|
||||
|
||||
val output_instruction = Output(UInt(Parameters.DataWidth))
|
||||
val output_instruction_address = Output(UInt(Parameters.AddrWidth))
|
||||
val output_regs_write_enable = Output(Bool())
|
||||
val output_regs_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val output_reg1_data = Output(UInt(Parameters.DataWidth))
|
||||
val output_reg2_data = Output(UInt(Parameters.DataWidth))
|
||||
val output_op1 = Output(UInt(Parameters.DataWidth))
|
||||
val output_op2 = Output(UInt(Parameters.DataWidth))
|
||||
val output_op1_jump = Output(UInt(Parameters.DataWidth))
|
||||
val output_op2_jump = Output(UInt(Parameters.DataWidth))
|
||||
val output_csr_write_enable = Output(Bool())
|
||||
val output_csr_write_address = Output(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val output_csr_read_data = Output(UInt(Parameters.DataWidth))
|
||||
})
|
||||
val write_enable = io.stall_flag < StallStates.ID
|
||||
val flush_enable = io.jump_flag
|
||||
|
||||
val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop))
|
||||
instruction.io.in := io.instruction
|
||||
instruction.io.write_enable := write_enable
|
||||
instruction.io.flush_enable := flush_enable
|
||||
io.output_instruction := instruction.io.out
|
||||
|
||||
val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress))
|
||||
instruction_address.io.in := io.instruction_address
|
||||
instruction_address.io.write_enable := write_enable
|
||||
instruction_address.io.flush_enable := flush_enable
|
||||
io.output_instruction_address := instruction_address.io.out
|
||||
|
||||
val regs_write_enable = Module(new PipelineRegister(1))
|
||||
regs_write_enable.io.in := io.regs_write_enable
|
||||
regs_write_enable.io.write_enable := write_enable
|
||||
regs_write_enable.io.flush_enable := flush_enable
|
||||
io.output_regs_write_enable := regs_write_enable.io.out
|
||||
|
||||
val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits))
|
||||
regs_write_address.io.in := io.regs_write_address
|
||||
regs_write_address.io.write_enable := write_enable
|
||||
regs_write_address.io.flush_enable := flush_enable
|
||||
io.output_regs_write_address := regs_write_address.io.out
|
||||
|
||||
val reg1_data = Module(new PipelineRegister())
|
||||
reg1_data.io.in := io.reg1_data
|
||||
reg1_data.io.write_enable := write_enable
|
||||
reg1_data.io.flush_enable := flush_enable
|
||||
io.output_reg1_data := reg1_data.io.out
|
||||
|
||||
val reg2_data = Module(new PipelineRegister())
|
||||
reg2_data.io.in := io.reg2_data
|
||||
reg2_data.io.write_enable := write_enable
|
||||
reg2_data.io.flush_enable := flush_enable
|
||||
io.output_reg2_data := reg2_data.io.out
|
||||
|
||||
val op1 = Module(new PipelineRegister())
|
||||
op1.io.in := io.op1
|
||||
op1.io.write_enable := write_enable
|
||||
op1.io.flush_enable := flush_enable
|
||||
io.output_op1 := op1.io.out
|
||||
|
||||
val op2 = Module(new PipelineRegister())
|
||||
op2.io.in := io.op2
|
||||
op2.io.write_enable := write_enable
|
||||
op2.io.flush_enable := flush_enable
|
||||
io.output_op2 := op2.io.out
|
||||
|
||||
val op1_jump = Module(new PipelineRegister())
|
||||
op1_jump.io.in := io.op1_jump
|
||||
op1_jump.io.write_enable := write_enable
|
||||
op1_jump.io.flush_enable := flush_enable
|
||||
io.output_op1_jump := op1_jump.io.out
|
||||
|
||||
val op2_jump = Module(new PipelineRegister())
|
||||
op2_jump.io.in := io.op2_jump
|
||||
op2_jump.io.write_enable := write_enable
|
||||
op2_jump.io.flush_enable := flush_enable
|
||||
io.output_op2_jump := op2_jump.io.out
|
||||
|
||||
val csr_write_enable = Module(new PipelineRegister())
|
||||
csr_write_enable.io.in := io.csr_write_enable
|
||||
csr_write_enable.io.write_enable := write_enable
|
||||
csr_write_enable.io.flush_enable := flush_enable
|
||||
io.output_csr_write_enable := csr_write_enable.io.out
|
||||
|
||||
val csr_write_address = Module(new PipelineRegister())
|
||||
csr_write_address.io.in := io.csr_write_address
|
||||
csr_write_address.io.write_enable := write_enable
|
||||
csr_write_address.io.flush_enable := flush_enable
|
||||
io.output_csr_write_address := csr_write_address.io.out
|
||||
|
||||
val csr_read_data = Module(new PipelineRegister())
|
||||
csr_read_data.io.in := io.csr_read_data
|
||||
csr_read_data.io.write_enable := write_enable
|
||||
csr_read_data.io.flush_enable := flush_enable
|
||||
io.output_csr_read_data := csr_read_data.io.out
|
||||
}
|
||||
53
mini-yatcpu/src/main/scala/riscv/core/threestage/IF2ID.scala
Normal file
53
mini-yatcpu/src/main/scala/riscv/core/threestage/IF2ID.scala
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.threestage
|
||||
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
|
||||
class IF2ID extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val instruction = Input(UInt(Parameters.InstructionWidth))
|
||||
val instruction_address = Input(UInt(Parameters.AddrWidth))
|
||||
val stall_flag = Input(UInt(Parameters.StallStateWidth))
|
||||
val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth))
|
||||
val jump_flag = Input(Bool())
|
||||
|
||||
val output_instruction = Output(UInt(Parameters.DataWidth))
|
||||
val output_instruction_address = Output(UInt(Parameters.AddrWidth))
|
||||
val output_interrupt_flag = Output(UInt(Parameters.InterruptFlagWidth))
|
||||
})
|
||||
|
||||
val write_enable = io.stall_flag < StallStates.IF
|
||||
val flush_enable = io.jump_flag
|
||||
|
||||
val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop))
|
||||
instruction.io.in := io.instruction
|
||||
instruction.io.write_enable := write_enable
|
||||
instruction.io.flush_enable := flush_enable
|
||||
io.output_instruction := instruction.io.out
|
||||
|
||||
val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress))
|
||||
instruction_address.io.in := io.instruction_address
|
||||
instruction_address.io.write_enable := write_enable
|
||||
instruction_address.io.flush_enable := flush_enable
|
||||
io.output_instruction_address := instruction_address.io.out
|
||||
|
||||
val interrupt_flag = Module(new PipelineRegister())
|
||||
interrupt_flag.io.in := io.interrupt_flag
|
||||
interrupt_flag.io.write_enable := write_enable
|
||||
interrupt_flag.io.flush_enable := flush_enable
|
||||
io.output_interrupt_flag := interrupt_flag.io.out
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.threestage
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import riscv.Parameters
|
||||
|
||||
|
||||
object InstructionTypes {
|
||||
val L = "b0000011".U
|
||||
val I = "b0010011".U
|
||||
val S = "b0100011".U
|
||||
val RM = "b0110011".U
|
||||
val B = "b1100011".U
|
||||
}
|
||||
|
||||
object Instructions {
|
||||
val lui = "b0110111".U
|
||||
val nop = "b0000001".U
|
||||
val jal = "b1101111".U
|
||||
val jalr = "b1100111".U
|
||||
val auipc = "b0010111".U
|
||||
val csr = "b1110011".U
|
||||
val fence = "b0001111".U
|
||||
}
|
||||
|
||||
object InstructionsTypeL {
|
||||
val lb = "b000".U
|
||||
val lh = "b001".U
|
||||
val lw = "b010".U
|
||||
val lbu = "b100".U
|
||||
val lhu = "b101".U
|
||||
}
|
||||
|
||||
object InstructionsTypeI {
|
||||
val addi = 0.U
|
||||
val slli = 1.U
|
||||
val slti = 2.U
|
||||
val sltiu = 3.U
|
||||
val xori = 4.U
|
||||
val sri = 5.U
|
||||
val ori = 6.U
|
||||
val andi = 7.U
|
||||
}
|
||||
|
||||
object InstructionsTypeS {
|
||||
val sb = "b000".U
|
||||
val sh = "b001".U
|
||||
val sw = "b010".U
|
||||
}
|
||||
|
||||
object InstructionsTypeR {
|
||||
val add_sub = 0.U
|
||||
val sll = 1.U
|
||||
val slt = 2.U
|
||||
val sltu = 3.U
|
||||
val xor = 4.U
|
||||
val sr = 5.U
|
||||
val or = 6.U
|
||||
val and = 7.U
|
||||
}
|
||||
|
||||
object InstructionsTypeM {
|
||||
val mul = 0.U
|
||||
val mulh = 1.U
|
||||
val mulhsu = 2.U
|
||||
val mulhum = 3.U
|
||||
val div = 4.U
|
||||
val divu = 5.U
|
||||
val rem = 6.U
|
||||
val remu = 7.U
|
||||
}
|
||||
|
||||
object InstructionsTypeB {
|
||||
val beq = "b000".U
|
||||
val bne = "b001".U
|
||||
val blt = "b100".U
|
||||
val bge = "b101".U
|
||||
val bltu = "b110".U
|
||||
val bgeu = "b111".U
|
||||
}
|
||||
|
||||
object InstructionsTypeCSR {
|
||||
val csrrw = "b001".U
|
||||
val csrrs = "b010".U
|
||||
val csrrc = "b011".U
|
||||
val csrrwi = "b101".U
|
||||
val csrrsi = "b110".U
|
||||
val csrrci = "b111".U
|
||||
}
|
||||
|
||||
object InstructionsNop {
|
||||
val nop = 0x00000013L.U(Parameters.DataWidth)
|
||||
}
|
||||
|
||||
object InstructionsRet {
|
||||
val mret = 0x30200073L.U(Parameters.DataWidth)
|
||||
val ret = 0x00008067L.U(Parameters.DataWidth)
|
||||
}
|
||||
|
||||
object InstructionsEnv {
|
||||
val ecall = 0x00000073L.U(Parameters.DataWidth)
|
||||
val ebreak = 0x00100073L.U(Parameters.DataWidth)
|
||||
}
|
||||
|
||||
class InstructionDecode extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val instruction = Input(UInt(Parameters.InstructionWidth))
|
||||
val instruction_address = Input(UInt(Parameters.AddrWidth))
|
||||
val reg1_data = Input(UInt(Parameters.DataWidth))
|
||||
val reg2_data = Input(UInt(Parameters.DataWidth))
|
||||
|
||||
val csr_read_data = Input(UInt(Parameters.DataWidth))
|
||||
|
||||
val regs_reg1_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val regs_reg2_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
|
||||
val ctrl_stall_flag = Output(UInt(Parameters.StallStateWidth))
|
||||
|
||||
val ex_op1 = Output(UInt(Parameters.DataWidth))
|
||||
val ex_op2 = Output(UInt(Parameters.DataWidth))
|
||||
val ex_op1_jump = Output(UInt(Parameters.DataWidth))
|
||||
val ex_op2_jump = Output(UInt(Parameters.DataWidth))
|
||||
val ex_instruction = Output(UInt(Parameters.DataWidth))
|
||||
val ex_instruction_address = Output(UInt(Parameters.AddrWidth))
|
||||
val ex_reg1_data = Output(UInt(Parameters.DataWidth))
|
||||
val ex_reg2_data = Output(UInt(Parameters.DataWidth))
|
||||
val ex_reg_write_enable = Output(Bool())
|
||||
val ex_reg_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
|
||||
val csr_read_address = Output(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val ex_csr_write_enable = Output(Bool())
|
||||
val ex_csr_write_address = Output(UInt(Parameters.CSRRegisterAddrWidth))
|
||||
val ex_csr_write_data = Output(UInt(Parameters.DataWidth))
|
||||
val ex_csr_read_data = Output(UInt(Parameters.DataWidth))
|
||||
})
|
||||
val opcode = io.instruction(6, 0)
|
||||
val funct3 = io.instruction(14, 12)
|
||||
val funct7 = io.instruction(31, 25)
|
||||
val rd = io.instruction(11, 7)
|
||||
val rs1 = io.instruction(19, 15)
|
||||
val rs2 = io.instruction(24, 20)
|
||||
|
||||
def disable_regs() = {
|
||||
disable_write()
|
||||
io.regs_reg1_read_address := 0.U
|
||||
io.regs_reg2_read_address := 0.U
|
||||
}
|
||||
|
||||
def disable_write() = {
|
||||
io.ex_reg_write_enable := false.B
|
||||
io.ex_reg_write_address := 0.U
|
||||
}
|
||||
|
||||
def enable_write(addr: UInt) = {
|
||||
io.ex_reg_write_enable := true.B
|
||||
io.ex_reg_write_address := addr
|
||||
}
|
||||
|
||||
io.ex_instruction := io.instruction
|
||||
io.ex_instruction_address := io.instruction_address
|
||||
io.ex_reg1_data := io.reg1_data
|
||||
io.ex_reg2_data := io.reg2_data
|
||||
io.ex_op1 := 0.U
|
||||
io.ex_op2 := 0.U
|
||||
io.ex_op1_jump := 0.U
|
||||
io.ex_op2_jump := 0.U
|
||||
io.ctrl_stall_flag := false.B
|
||||
io.csr_read_address := 0.U
|
||||
io.ex_csr_read_data := io.csr_read_data
|
||||
io.ex_csr_write_enable := false.B
|
||||
io.ex_csr_write_data := 0.U
|
||||
io.ex_csr_write_address := 0.U
|
||||
|
||||
when(opcode === InstructionTypes.L) {
|
||||
when(
|
||||
funct3 === InstructionsTypeL.lb ||
|
||||
funct3 === InstructionsTypeL.lh ||
|
||||
funct3 === InstructionsTypeL.lw ||
|
||||
funct3 === InstructionsTypeL.lbu ||
|
||||
funct3 === InstructionsTypeL.lhu
|
||||
) {
|
||||
enable_write(rd)
|
||||
io.regs_reg1_read_address := rs1
|
||||
io.regs_reg2_read_address := 0.U
|
||||
io.ex_op1 := io.reg1_data
|
||||
io.ex_op2 := Cat(Fill(20, io.instruction(31)), io.instruction(31, 20))
|
||||
}.otherwise {
|
||||
disable_regs()
|
||||
}
|
||||
}.elsewhen(opcode === InstructionTypes.I) {
|
||||
enable_write(rd)
|
||||
io.regs_reg1_read_address := rs1
|
||||
io.regs_reg2_read_address := 0.U
|
||||
io.ex_op1 := io.reg1_data
|
||||
io.ex_op2 := Cat(Fill(20, io.instruction(31)), io.instruction(31, 20))
|
||||
}.elsewhen(opcode === InstructionTypes.S) {
|
||||
when(funct3 === InstructionsTypeS.sb ||
|
||||
funct3 === InstructionsTypeS.sh ||
|
||||
funct3 === InstructionsTypeS.sw) {
|
||||
disable_write()
|
||||
io.regs_reg1_read_address := rs1
|
||||
io.regs_reg2_read_address := rs2
|
||||
io.ex_op1 := io.reg1_data
|
||||
io.ex_op2 := Cat(Fill(20, io.instruction(31)), io.instruction(31, 25), io.instruction(11, 7))
|
||||
}.otherwise {
|
||||
disable_regs()
|
||||
}
|
||||
}.elsewhen(opcode === InstructionTypes.RM) {
|
||||
when(funct7 === 0.U || funct7 === 0x20.U) {
|
||||
enable_write(rd)
|
||||
io.regs_reg1_read_address := rs1
|
||||
io.regs_reg2_read_address := rs2
|
||||
io.ex_op1 := io.reg1_data
|
||||
io.ex_op2 := io.reg2_data
|
||||
}.otherwise {
|
||||
// TODO(howard): implement mul and div
|
||||
disable_regs()
|
||||
}
|
||||
}.elsewhen(opcode === InstructionTypes.B) {
|
||||
when(
|
||||
funct3 === InstructionsTypeB.beq ||
|
||||
funct3 === InstructionsTypeB.bne ||
|
||||
funct3 === InstructionsTypeB.blt ||
|
||||
funct3 === InstructionsTypeB.bge ||
|
||||
funct3 === InstructionsTypeB.bltu ||
|
||||
funct3 === InstructionsTypeB.bgeu
|
||||
) {
|
||||
disable_write()
|
||||
io.regs_reg1_read_address := rs1
|
||||
io.regs_reg2_read_address := rs2
|
||||
io.ex_op1 := io.reg1_data
|
||||
io.ex_op2 := io.reg2_data
|
||||
io.ex_op1_jump := io.instruction_address
|
||||
io.ex_op2_jump := Cat(Fill(20, io.instruction(31)), io.instruction(7), io.instruction(30, 25), io.instruction
|
||||
(11, 8), 0.U(1.W))
|
||||
}.otherwise {
|
||||
disable_regs()
|
||||
}
|
||||
}.elsewhen(opcode === Instructions.jal) {
|
||||
enable_write(rd)
|
||||
io.regs_reg1_read_address := 0.U
|
||||
io.regs_reg2_read_address := 0.U
|
||||
io.ex_op1 := io.instruction_address
|
||||
io.ex_op2 := 4.U
|
||||
io.ex_op1_jump := io.instruction_address
|
||||
io.ex_op2_jump := Cat(Fill(12, io.instruction(31)), io.instruction(19, 12), io.instruction(20), io.instruction
|
||||
(30, 21), 0.U(1.W))
|
||||
}.elsewhen(opcode === Instructions.jalr) {
|
||||
enable_write(rd)
|
||||
io.regs_reg1_read_address := rs1
|
||||
io.regs_reg2_read_address := 0.U
|
||||
io.ex_op1 := io.instruction_address
|
||||
io.ex_op2 := 4.U
|
||||
io.ex_op1_jump := io.reg1_data
|
||||
io.ex_op2_jump := Cat(Fill(20, io.instruction(31)), io.instruction(31, 20))
|
||||
}.elsewhen(opcode === Instructions.lui) {
|
||||
enable_write(rd)
|
||||
io.regs_reg1_read_address := 0.U
|
||||
io.regs_reg2_read_address := 0.U
|
||||
io.ex_op1 := Cat(io.instruction(31, 12), Fill(12, 0.U(1.W)))
|
||||
io.ex_op2 := 0.U
|
||||
}.elsewhen(opcode === Instructions.auipc) {
|
||||
enable_write(rd)
|
||||
io.regs_reg1_read_address := 0.U
|
||||
io.regs_reg2_read_address := 0.U
|
||||
io.ex_op1 := io.instruction_address
|
||||
io.ex_op2 := Cat(io.instruction(31, 12), Fill(12, 0.U(1.W)))
|
||||
}.elsewhen(opcode === Instructions.csr) {
|
||||
disable_regs()
|
||||
io.csr_read_address := Cat(0.U(20.W), io.instruction(31, 20))
|
||||
io.ex_csr_write_address := Cat(0.U(20.W), io.instruction(31, 20))
|
||||
when(
|
||||
funct3 === InstructionsTypeCSR.csrrc ||
|
||||
funct3 === InstructionsTypeCSR.csrrs ||
|
||||
funct3 === InstructionsTypeCSR.csrrw
|
||||
) {
|
||||
io.regs_reg1_read_address := rs1
|
||||
io.regs_reg2_read_address := 0.U
|
||||
io.ex_reg_write_enable := true.B
|
||||
io.ex_reg_write_address := rd
|
||||
io.ex_csr_write_enable := true.B
|
||||
}.elsewhen(
|
||||
funct3 === InstructionsTypeCSR.csrrci ||
|
||||
funct3 === InstructionsTypeCSR.csrrsi ||
|
||||
funct3 === InstructionsTypeCSR.csrrwi
|
||||
) {
|
||||
io.regs_reg1_read_address := 0.U
|
||||
io.regs_reg2_read_address := 0.U
|
||||
io.ex_reg_write_enable := true.B
|
||||
io.ex_reg_write_address := rd
|
||||
io.ex_csr_write_enable := true.B
|
||||
}.otherwise {
|
||||
io.ex_csr_write_enable := false.B
|
||||
io.ex_csr_write_data := 0.U
|
||||
io.ex_csr_write_address := 0.U
|
||||
}
|
||||
}.elsewhen(opcode === Instructions.nop) {
|
||||
disable_regs()
|
||||
}.otherwise {
|
||||
disable_regs()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.threestage
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util.MuxCase
|
||||
import riscv.Parameters
|
||||
|
||||
object ProgramCounter {
|
||||
val EntryAddress = Parameters.EntryAddress
|
||||
}
|
||||
|
||||
class InstructionFetch extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val stall_flag_ctrl = Input(Bool())
|
||||
val jump_flag_ctrl = Input(Bool())
|
||||
val jump_address_ctrl = Input(UInt(Parameters.AddrWidth))
|
||||
val instruction_valid = Input(Bool())
|
||||
|
||||
val bus_request = Output(Bool())
|
||||
val bus_address = Output(UInt(Parameters.AddrWidth))
|
||||
val bus_data = Input(UInt(Parameters.InstructionWidth))
|
||||
val bus_read = Output(Bool())
|
||||
|
||||
val ctrl_stall_flag = Output(Bool())
|
||||
val id_instruction_address = Output(UInt(Parameters.AddrWidth))
|
||||
val id_instruction = Output(UInt(Parameters.InstructionWidth))
|
||||
})
|
||||
val instruction_address = RegInit(ProgramCounter.EntryAddress)
|
||||
val pending_jump = RegInit(false.B)
|
||||
val pc = RegInit(ProgramCounter.EntryAddress)
|
||||
io.bus_read := true.B
|
||||
io.bus_request := true.B
|
||||
|
||||
pc := MuxCase(
|
||||
pc + 4.U,
|
||||
IndexedSeq(
|
||||
io.jump_flag_ctrl -> io.jump_address_ctrl,
|
||||
(io.stall_flag_ctrl >= StallStates.PC) -> pc
|
||||
)
|
||||
)
|
||||
when(!io.instruction_valid) {
|
||||
when(io.jump_flag_ctrl) {
|
||||
pending_jump := true.B
|
||||
}
|
||||
}
|
||||
when(io.instruction_valid) {
|
||||
when(pending_jump) {
|
||||
pending_jump := false.B
|
||||
}
|
||||
}
|
||||
io.id_instruction := Mux(io.instruction_valid && !io.jump_flag_ctrl && !pending_jump, io.bus_data,
|
||||
InstructionsNop.nop)
|
||||
io.ctrl_stall_flag := !io.instruction_valid || pending_jump
|
||||
io.id_instruction_address := pc
|
||||
io.bus_address := pc
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.threestage
|
||||
|
||||
import chisel3._
|
||||
import riscv.Parameters
|
||||
|
||||
class PipelineRegister(width: Int = Parameters.DataBits, defaultValue: UInt = 0.U) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val write_enable = Input(Bool())
|
||||
val flush_enable = Input(Bool())
|
||||
val in = Input(UInt(width.W))
|
||||
val out = Output(UInt(width.W))
|
||||
})
|
||||
|
||||
val reg = RegInit(UInt(width.W), defaultValue)
|
||||
when(io.write_enable) {
|
||||
reg := io.in
|
||||
}.elsewhen(io.flush_enable) {
|
||||
reg := defaultValue
|
||||
}
|
||||
io.out := reg
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.core.threestage
|
||||
|
||||
import chisel3._
|
||||
import chisel3.util._
|
||||
import riscv.Parameters
|
||||
|
||||
object Registers extends Enumeration {
|
||||
type Register = Value
|
||||
val zero,
|
||||
ra, sp, gp, tp,
|
||||
t0, t1, t2, fp,
|
||||
s1,
|
||||
a0, a1, a2, a3, a4, a5, a6, a7,
|
||||
s2, s3, s4, s5, s6, s7, s8, s9, s10, s11,
|
||||
t3, t4, t5, t6 = Value
|
||||
}
|
||||
|
||||
class RegisterFile extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val write_enable = Input(Bool())
|
||||
val write_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val write_data = Input(UInt(Parameters.DataWidth))
|
||||
|
||||
val read_address1 = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val read_address2 = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val read_data1 = Output(UInt(Parameters.DataWidth))
|
||||
val read_data2 = Output(UInt(Parameters.DataWidth))
|
||||
|
||||
val debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val debug_read_data = Output(UInt(Parameters.DataWidth))
|
||||
})
|
||||
val registers = Reg(Vec(Parameters.PhysicalRegisters, UInt(Parameters.DataWidth)))
|
||||
|
||||
when(!reset.asBool) {
|
||||
when(io.write_enable && io.write_address =/= 0.U) {
|
||||
registers(io.write_address) := io.write_data
|
||||
}
|
||||
}
|
||||
|
||||
io.read_data1 := MuxCase(
|
||||
registers(io.read_address1),
|
||||
IndexedSeq(
|
||||
(io.read_address1 === 0.U) -> 0.U,
|
||||
(io.read_address1 === io.write_address && io.write_enable) -> io.write_data
|
||||
)
|
||||
)
|
||||
|
||||
io.read_data2 := MuxCase(
|
||||
registers(io.read_address2),
|
||||
IndexedSeq(
|
||||
(io.read_address2 === 0.U) -> 0.U,
|
||||
(io.read_address2 === io.write_address && io.write_enable) -> io.write_data
|
||||
)
|
||||
)
|
||||
|
||||
io.debug_read_data := MuxCase(
|
||||
registers(io.debug_read_address),
|
||||
IndexedSeq(
|
||||
(io.debug_read_address === 0.U) -> 0.U,
|
||||
(io.debug_read_address === io.write_address && io.write_enable) -> io.write_data
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
33
mini-yatcpu/src/main/scala/riscv/debug/DebugModule.scala
Normal file
33
mini-yatcpu/src/main/scala/riscv/debug/DebugModule.scala
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.debug
|
||||
|
||||
import chisel3._
|
||||
|
||||
object DMRegisters {
|
||||
val DATA0 = 0x04.U
|
||||
val DATA11 = 0x0F.U
|
||||
val DMCONTROL = 0x10.U
|
||||
val DMSTATUS = 0x11.U
|
||||
val HARTINFO = 0x12.U
|
||||
val ABSTRACTCS = 0x16.U
|
||||
val COMMAND = 0x17.U
|
||||
}
|
||||
|
||||
class DebugModule extends Module {
|
||||
val io = IO(new Bundle {
|
||||
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.debug
|
||||
|
||||
import chisel3._
|
||||
|
||||
object DTMRegisters {
|
||||
val IDCODE = 0x01.U
|
||||
val DTMCS = 0x10.U
|
||||
val DMI = 0x11.U
|
||||
val BYPASS1F = 0x1F.U
|
||||
}
|
||||
|
||||
class DebugTransportModule extends Module {
|
||||
val io = IO(new Bundle {
|
||||
|
||||
})
|
||||
|
||||
val idcode = 0x1e200151.U
|
||||
val dtmcs = RegInit("b00000000000000000101000011100001".U)
|
||||
val dmi = RegInit(UInt(48.W))
|
||||
}
|
||||
25
mini-yatcpu/src/test/scala/riscv/BoardTest.scala
Normal file
25
mini-yatcpu/src/test/scala/riscv/BoardTest.scala
Normal file
@@ -0,0 +1,25 @@
|
||||
package riscv
|
||||
|
||||
import board.z710.Top
|
||||
|
||||
import riscv.{Parameters, TestAnnotations}
|
||||
import chisel3._
|
||||
import chisel3.util.{is, switch}
|
||||
import chiseltest._
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import board.z710.Top
|
||||
|
||||
|
||||
class SayGoodbyeTest extends AnyFlatSpec with ChiselScalatestTester {
|
||||
behavior of "Board simulation"
|
||||
it should "say goodbye " in {
|
||||
test(new Top("say_goodbye.asmbin")).withAnnotations(TestAnnotations.annos) { c =>
|
||||
|
||||
for (i <- 1 to 50000) {
|
||||
c.clock.step(5)
|
||||
c.io.rx.poke((i % 2).U) // poke some useless value, since rx not yet used
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
164
mini-yatcpu/src/test/scala/riscv/PeripheralTest.scala
Normal file
164
mini-yatcpu/src/test/scala/riscv/PeripheralTest.scala
Normal file
@@ -0,0 +1,164 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv
|
||||
|
||||
import bus.{AXI4LiteMaster, AXI4LiteMasterBundle, AXI4LiteSlave, AXI4LiteSlaveBundle}
|
||||
import chisel3._
|
||||
import chiseltest._
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import peripheral.{Memory, ROMLoader}
|
||||
|
||||
class TimerTest extends AnyFlatSpec with ChiselScalatestTester {
|
||||
class TestTimerLimit extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val limit = Output(UInt())
|
||||
val bundle = new AXI4LiteMasterBundle(Parameters.AddrBits, Parameters.DataBits)
|
||||
})
|
||||
val timer = Module(new peripheral.Timer)
|
||||
val master = Module(new AXI4LiteMaster(Parameters.AddrBits, Parameters.DataBits))
|
||||
io.limit := timer.io.debug_limit
|
||||
master.io.bundle <> io.bundle
|
||||
timer.io.channels <> master.io.channels
|
||||
}
|
||||
|
||||
behavior of "Timer"
|
||||
it should "read and write the limit" in {
|
||||
test(new TestTimerLimit).withAnnotations(TestAnnotations.annos) {
|
||||
c =>
|
||||
c.io.bundle.read.poke(false.B)
|
||||
c.io.bundle.write.poke(true.B)
|
||||
c.io.bundle.address.poke(0x4.U)
|
||||
c.io.bundle.write_data.poke(0x990315.U)
|
||||
c.clock.step()
|
||||
c.io.bundle.busy.expect(true.B)
|
||||
c.io.bundle.write.poke(false.B)
|
||||
c.io.bundle.address.poke(0x0.U)
|
||||
c.io.bundle.write_data.poke(0.U)
|
||||
c.clock.step(8)
|
||||
c.io.bundle.busy.expect(false.B)
|
||||
c.io.bundle.write_valid.expect(true.B)
|
||||
c.io.limit.expect(0x990315.U)
|
||||
c.io.bundle.read.poke(true.B)
|
||||
c.io.bundle.address.poke(0x4.U)
|
||||
c.clock.step()
|
||||
c.io.bundle.busy.expect(true.B)
|
||||
c.clock.step(6)
|
||||
c.io.bundle.busy.expect(false.B)
|
||||
c.io.bundle.read_valid.expect(true.B)
|
||||
c.io.bundle.read_data.expect(0x990315.U)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MemoryTest extends AnyFlatSpec with ChiselScalatestTester {
|
||||
class MemoryTest extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val bundle = new AXI4LiteMasterBundle(Parameters.AddrBits, Parameters.DataBits)
|
||||
|
||||
val write_strobe = Input(UInt(4.W))
|
||||
})
|
||||
val memory = Module(new Memory(4096))
|
||||
val master = Module(new AXI4LiteMaster(Parameters.AddrBits, Parameters.DataBits))
|
||||
|
||||
master.io.bundle <> io.bundle
|
||||
master.io.bundle.write_strobe := VecInit(io.write_strobe.asBools)
|
||||
master.io.channels <> memory.io.channels
|
||||
|
||||
memory.io.debug_read_address := 0.U
|
||||
}
|
||||
|
||||
behavior of "Memory"
|
||||
it should "perform read and write" in {
|
||||
test(new MemoryTest).withAnnotations(TestAnnotations.annos) { c =>
|
||||
c.io.bundle.read.poke(false.B)
|
||||
c.io.bundle.write.poke(true.B)
|
||||
c.io.write_strobe.poke(0xF.U)
|
||||
c.io.bundle.address.poke(0x4.U)
|
||||
c.io.bundle.write_data.poke(0xDEADBEEFL.U)
|
||||
c.clock.step()
|
||||
c.io.bundle.busy.expect(true.B)
|
||||
c.io.bundle.write.poke(false.B)
|
||||
c.io.bundle.address.poke(0x0.U)
|
||||
c.io.bundle.write_data.poke(0.U)
|
||||
c.clock.step(8)
|
||||
c.io.bundle.busy.expect(false.B)
|
||||
c.io.bundle.write_valid.expect(true.B)
|
||||
c.io.bundle.read.poke(true.B)
|
||||
c.io.bundle.address.poke(0x4.U)
|
||||
c.clock.step()
|
||||
c.io.bundle.busy.expect(true.B)
|
||||
c.clock.step(6)
|
||||
c.io.bundle.busy.expect(false.B)
|
||||
c.io.bundle.read_valid.expect(true.B)
|
||||
c.io.bundle.read_data.expect(0xDEADBEEFL.U)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ROMLoaderTest extends AnyFlatSpec with ChiselScalatestTester {
|
||||
|
||||
class ROMLoaderTest extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val rom_address = Output(UInt(32.W))
|
||||
val rom_data = Input(UInt(32.W))
|
||||
val load_start = Input(Bool())
|
||||
val load_address = Input(UInt(32.W))
|
||||
val load_finished = Output(Bool())
|
||||
|
||||
val bundle = new AXI4LiteSlaveBundle(32, 32)
|
||||
})
|
||||
|
||||
val rom_loader = Module(new ROMLoader(2))
|
||||
rom_loader.io.rom_data := io.rom_data
|
||||
rom_loader.io.load_start := io.load_start
|
||||
rom_loader.io.load_address := io.load_address
|
||||
io.load_finished := rom_loader.io.load_finished
|
||||
io.rom_address := rom_loader.io.rom_address
|
||||
|
||||
val slave = Module(new AXI4LiteSlave(Parameters.AddrBits, Parameters.DataBits))
|
||||
slave.io.bundle <> io.bundle
|
||||
slave.io.channels <> rom_loader.io.channels
|
||||
slave.io.bundle.read_data := 0.U
|
||||
}
|
||||
|
||||
|
||||
behavior of "ROMLoader"
|
||||
it should "load program" in {
|
||||
test(new ROMLoaderTest).withAnnotations(TestAnnotations.annos) { c =>
|
||||
c.io.load_address.poke(0x100.U)
|
||||
c.io.load_start.poke(true.B)
|
||||
c.clock.step()
|
||||
c.io.load_start.poke(false.B)
|
||||
c.io.rom_address.expect(0x0.U)
|
||||
c.clock.step(8)
|
||||
c.io.bundle.write.expect(true.B)
|
||||
c.io.bundle.address.expect(0x100.U)
|
||||
c.clock.step(4)
|
||||
c.io.rom_address.expect(0x1.U)
|
||||
c.clock.step(7)
|
||||
c.io.rom_address.expect(0x1.U)
|
||||
c.io.bundle.write.expect(true.B)
|
||||
c.io.bundle.address.expect(0x104.U)
|
||||
c.clock.step()
|
||||
c.io.rom_address.expect(0x1.U)
|
||||
c.clock.step(3)
|
||||
c.io.load_finished.expect(true.B)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
52
mini-yatcpu/src/test/scala/riscv/TestAnnotations.scala
Normal file
52
mini-yatcpu/src/test/scala/riscv/TestAnnotations.scala
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright 2022 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv
|
||||
|
||||
import chiseltest.{VerilatorBackendAnnotation, WriteVcdAnnotation}
|
||||
import firrtl.AnnotationSeq
|
||||
|
||||
import java.nio.file.{Files, Paths}
|
||||
|
||||
object VerilatorEnabler {
|
||||
val annos: AnnotationSeq = if (sys.env.contains("Path")) {
|
||||
if (sys.env.getOrElse("Path", "").split(";").exists(path => {
|
||||
Files.exists(Paths.get(path, "verilator"))
|
||||
})) {
|
||||
Seq(VerilatorBackendAnnotation)
|
||||
} else {
|
||||
Seq()
|
||||
}
|
||||
} else {
|
||||
if (sys.env.getOrElse("PATH", "").split(":").exists(path => {
|
||||
Files.exists(Paths.get(path, "verilator"))
|
||||
})) {
|
||||
Seq(VerilatorBackendAnnotation)
|
||||
} else {
|
||||
Seq()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object WriteVcdEnabler {
|
||||
val annos: AnnotationSeq = if (sys.env.contains("WRITE_VCD")) {
|
||||
Seq(WriteVcdAnnotation)
|
||||
} else {
|
||||
Seq()
|
||||
}
|
||||
}
|
||||
|
||||
object TestAnnotations {
|
||||
val annos = VerilatorEnabler.annos ++ WriteVcdEnabler.annos
|
||||
}
|
||||
184
mini-yatcpu/src/test/scala/riscv/fivestage/CPUTest.scala
Normal file
184
mini-yatcpu/src/test/scala/riscv/fivestage/CPUTest.scala
Normal file
@@ -0,0 +1,184 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.fivestage
|
||||
|
||||
import board.basys3.BootStates
|
||||
import bus.BusSwitch
|
||||
import chisel3._
|
||||
import chisel3.util.{is, switch}
|
||||
import chiseltest._
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import peripheral.{DummySlave, Memory, ROMLoader}
|
||||
import riscv.core.fivestage.{CPU, ProgramCounter}
|
||||
import riscv.{Parameters, TestAnnotations}
|
||||
|
||||
import java.nio.{ByteBuffer, ByteOrder}
|
||||
|
||||
class TestInstructionROM(asmBin: String) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val address = Input(UInt(32.W))
|
||||
val data = Output(UInt(32.W))
|
||||
})
|
||||
|
||||
val (insts, capacity) = loadAsmBinary(asmBin)
|
||||
val mem = RegInit(insts)
|
||||
io.data := mem(io.address)
|
||||
|
||||
def loadAsmBinary(filename: String) = {
|
||||
val inputStream = getClass.getClassLoader.getResourceAsStream(filename)
|
||||
var instructions = new Array[BigInt](0)
|
||||
val arr = new Array[Byte](4)
|
||||
while (inputStream.read(arr) == 4) {
|
||||
val instBuf = ByteBuffer.wrap(arr)
|
||||
instBuf.order(ByteOrder.LITTLE_ENDIAN)
|
||||
val inst = BigInt(instBuf.getInt() & 0xFFFFFFFFL)
|
||||
instructions = instructions :+ inst
|
||||
}
|
||||
(VecInit((instructions.map(inst => inst.U(32.W))).toIndexedSeq), instructions.length)
|
||||
}
|
||||
}
|
||||
|
||||
class TestTopModule(exeFilename: String) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val mem_debug_read_address = Input(UInt(Parameters.AddrWidth))
|
||||
val regs_debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val regs_debug_read_data = Output(UInt(Parameters.DataWidth))
|
||||
val mem_debug_read_data = Output(UInt(Parameters.DataWidth))
|
||||
|
||||
val interrupt = Input(UInt(Parameters.InterruptFlagWidth))
|
||||
val boot_state = Output(UInt())
|
||||
})
|
||||
val boot_state = RegInit(BootStates.Init)
|
||||
io.boot_state := boot_state.asUInt
|
||||
val instruction_rom = Module(new TestInstructionROM(exeFilename))
|
||||
val rom_loader = Module(new ROMLoader(instruction_rom.capacity))
|
||||
val mem = Module(new Memory(8192))
|
||||
val cpu = Module(new CPU)
|
||||
val timer = Module(new peripheral.Timer)
|
||||
val bus_switch = Module(new BusSwitch)
|
||||
val dummy = Module(new DummySlave)
|
||||
bus_switch.io.master <> cpu.io.axi4_channels
|
||||
bus_switch.io.address := cpu.io.bus_address
|
||||
for (i <- 0 until Parameters.SlaveDeviceCount) {
|
||||
bus_switch.io.slaves(i) <> dummy.io.channels
|
||||
}
|
||||
rom_loader.io.load_address := ProgramCounter.EntryAddress
|
||||
rom_loader.io.rom_data := instruction_rom.io.data
|
||||
rom_loader.io.load_start := false.B
|
||||
instruction_rom.io.address := rom_loader.io.rom_address
|
||||
cpu.io.stall_flag_bus := true.B
|
||||
cpu.io.instruction_valid := false.B
|
||||
bus_switch.io.slaves(0) <> mem.io.channels
|
||||
rom_loader.io.channels <> dummy.io.channels
|
||||
switch(boot_state) {
|
||||
is(BootStates.Init) {
|
||||
rom_loader.io.load_start := true.B
|
||||
boot_state := BootStates.Loading
|
||||
rom_loader.io.channels <> mem.io.channels
|
||||
}
|
||||
is(BootStates.Loading) {
|
||||
rom_loader.io.load_start := false.B
|
||||
rom_loader.io.channels <> mem.io.channels
|
||||
when(rom_loader.io.load_finished) {
|
||||
boot_state := BootStates.Finished
|
||||
}
|
||||
}
|
||||
is(BootStates.Finished) {
|
||||
rom_loader.io.load_start := false.B
|
||||
cpu.io.stall_flag_bus := false.B
|
||||
cpu.io.instruction_valid := true.B
|
||||
}
|
||||
}
|
||||
bus_switch.io.slaves(4) <> timer.io.channels
|
||||
|
||||
mem.io.debug_read_address := io.mem_debug_read_address
|
||||
cpu.io.debug_read_address := io.regs_debug_read_address
|
||||
io.regs_debug_read_data := cpu.io.debug_read_data
|
||||
io.mem_debug_read_data := mem.io.debug_read_data
|
||||
|
||||
cpu.io.interrupt_flag := io.interrupt
|
||||
}
|
||||
|
||||
|
||||
class FibonacciTest extends AnyFlatSpec with ChiselScalatestTester {
|
||||
behavior of "Five Stage CPU"
|
||||
it should "calculate recursively fibonacci(10)" in {
|
||||
test(new TestTopModule("fibonacci.asmbin")).withAnnotations(TestAnnotations.annos) { c =>
|
||||
c.io.interrupt.poke(0.U)
|
||||
for (i <- 1 to 100) {
|
||||
c.clock.step(1000)
|
||||
c.io.mem_debug_read_address.poke((i * 4).U) // Avoid timeout
|
||||
}
|
||||
|
||||
c.io.mem_debug_read_address.poke(4.U)
|
||||
c.clock.step()
|
||||
c.io.mem_debug_read_data.expect(55.U)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class QuicksortTest extends AnyFlatSpec with ChiselScalatestTester {
|
||||
behavior of "Five Stage CPU"
|
||||
it should "quicksort 10 numbers" in {
|
||||
test(new TestTopModule("quicksort.asmbin")).withAnnotations(TestAnnotations.annos) { c =>
|
||||
c.io.interrupt.poke(0.U)
|
||||
for (i <- 1 to 50) {
|
||||
c.clock.step(1000)
|
||||
c.io.mem_debug_read_address.poke((i * 4).U) // Avoid timeout
|
||||
}
|
||||
for (i <- 1 to 10) {
|
||||
c.io.mem_debug_read_address.poke((4 * i).U)
|
||||
c.clock.step()
|
||||
c.io.mem_debug_read_data.expect((i - 1).U)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MMIOTest extends AnyFlatSpec with ChiselScalatestTester {
|
||||
behavior of "Five Stage CPU"
|
||||
it should "read and write timer register" in {
|
||||
test(new TestTopModule("mmio.asmbin")).withAnnotations(TestAnnotations.annos) { c =>
|
||||
c.io.interrupt.poke(0.U)
|
||||
for (i <- 1 to 1000) {
|
||||
c.clock.step()
|
||||
c.io.mem_debug_read_address.poke((i * 4).U) // Avoid timeout
|
||||
}
|
||||
c.io.regs_debug_read_address.poke(5.U)
|
||||
c.io.regs_debug_read_data.expect(100000000.U)
|
||||
c.io.regs_debug_read_address.poke(6.U)
|
||||
c.io.regs_debug_read_data.expect(0xBEEF.U)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ByteAccessTest extends AnyFlatSpec with ChiselScalatestTester {
|
||||
behavior of "Five Stage CPU"
|
||||
it should "store and load single byte" in {
|
||||
test(new TestTopModule("sb.asmbin")).withAnnotations(TestAnnotations.annos) { c =>
|
||||
c.io.interrupt.poke(0.U)
|
||||
for (i <- 1 to 500) {
|
||||
c.clock.step()
|
||||
c.io.mem_debug_read_address.poke((i * 4).U) // Avoid timeout
|
||||
}
|
||||
c.io.regs_debug_read_address.poke(5.U)
|
||||
c.io.regs_debug_read_data.expect(0xDEADBEEFL.U)
|
||||
c.io.regs_debug_read_address.poke(6.U)
|
||||
c.io.regs_debug_read_data.expect(0xEF.U)
|
||||
c.io.regs_debug_read_address.poke(1.U)
|
||||
c.io.regs_debug_read_data.expect(0x15EF.U)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.fivestage
|
||||
|
||||
import chisel3._
|
||||
import chiseltest._
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import riscv.TestAnnotations
|
||||
import riscv.core.fivestage.RegisterFile
|
||||
|
||||
class RegisterFileTest extends AnyFlatSpec with ChiselScalatestTester {
|
||||
behavior of "Register File of Five-stage CPU"
|
||||
it should "read the written content" in {
|
||||
test(new RegisterFile).withAnnotations(TestAnnotations.annos) { c =>
|
||||
timescope {
|
||||
c.io.write_enable.poke(true.B)
|
||||
c.io.write_address.poke(1.U)
|
||||
c.io.write_data.poke(0xDEADBEEFL.U)
|
||||
c.clock.step()
|
||||
}
|
||||
c.io.read_address1.poke(1.U)
|
||||
c.io.read_data1.expect(0xDEADBEEFL.U)
|
||||
}
|
||||
}
|
||||
|
||||
it should "x0 always be zero" in {
|
||||
test(new RegisterFile).withAnnotations(TestAnnotations.annos) { c =>
|
||||
timescope {
|
||||
c.io.write_enable.poke(true.B)
|
||||
c.io.write_address.poke(0.U)
|
||||
c.io.write_data.poke(0xDEADBEEFL.U)
|
||||
c.clock.step()
|
||||
}
|
||||
c.io.read_address1.poke(0.U)
|
||||
c.io.read_data1.expect(0.U)
|
||||
}
|
||||
}
|
||||
|
||||
it should "read the writing content" in {
|
||||
test(new RegisterFile).withAnnotations(TestAnnotations.annos) { c =>
|
||||
timescope {
|
||||
c.io.read_address1.poke(2.U)
|
||||
c.io.read_data1.expect(0.U)
|
||||
c.io.write_enable.poke(true.B)
|
||||
c.io.write_address.poke(2.U)
|
||||
c.io.write_data.poke(0xDEADBEEFL.U)
|
||||
c.io.read_address1.poke(2.U)
|
||||
c.io.read_data1.expect(0xDEADBEEFL.U)
|
||||
c.clock.step()
|
||||
}
|
||||
c.io.read_address1.poke(2.U)
|
||||
c.io.read_data1.expect(0xDEADBEEFL.U)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
185
mini-yatcpu/src/test/scala/riscv/threestage/CPUTest.scala
Normal file
185
mini-yatcpu/src/test/scala/riscv/threestage/CPUTest.scala
Normal file
@@ -0,0 +1,185 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.threestage
|
||||
|
||||
import board.basys3.BootStates
|
||||
import bus.BusSwitch
|
||||
import chisel3._
|
||||
import chisel3.util.{is, switch}
|
||||
import chiseltest._
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import peripheral.{DummySlave, Memory, ROMLoader}
|
||||
import riscv.core.threestage.{CPU, ProgramCounter}
|
||||
import riscv.{Parameters, TestAnnotations}
|
||||
|
||||
import java.nio.{ByteBuffer, ByteOrder}
|
||||
|
||||
class TestInstructionROM(asmBin: String) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val address = Input(UInt(32.W))
|
||||
val data = Output(UInt(32.W))
|
||||
})
|
||||
|
||||
val (insts, capacity) = loadAsmBinary(asmBin)
|
||||
val mem = RegInit(insts)
|
||||
io.data := mem(io.address)
|
||||
|
||||
def loadAsmBinary(filename: String) = {
|
||||
val inputStream = getClass.getClassLoader.getResourceAsStream(filename)
|
||||
var instructions = new Array[BigInt](0)
|
||||
val arr = new Array[Byte](4)
|
||||
while (inputStream.read(arr) == 4) {
|
||||
val instBuf = ByteBuffer.wrap(arr)
|
||||
instBuf.order(ByteOrder.LITTLE_ENDIAN)
|
||||
val inst = BigInt(instBuf.getInt() & 0xFFFFFFFFL)
|
||||
instructions = instructions :+ inst
|
||||
}
|
||||
(VecInit((instructions.map(inst => inst.U(32.W))).toIndexedSeq), instructions.length)
|
||||
}
|
||||
}
|
||||
|
||||
class TestTopModule(exeFilename: String) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val mem_debug_read_address = Input(UInt(Parameters.AddrWidth))
|
||||
val regs_debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||
val regs_debug_read_data = Output(UInt(Parameters.DataWidth))
|
||||
val mem_debug_read_data = Output(UInt(Parameters.DataWidth))
|
||||
|
||||
val interrupt = Input(UInt(Parameters.InterruptFlagWidth))
|
||||
val boot_state = Output(UInt())
|
||||
})
|
||||
val boot_state = RegInit(BootStates.Init)
|
||||
io.boot_state := boot_state.asUInt
|
||||
val instruction_rom = Module(new TestInstructionROM(exeFilename))
|
||||
val rom_loader = Module(new ROMLoader(instruction_rom.capacity))
|
||||
val mem = Module(new Memory(8192))
|
||||
val cpu = Module(new CPU)
|
||||
val timer = Module(new peripheral.Timer)
|
||||
val bus_switch = Module(new BusSwitch)
|
||||
val dummy = Module(new DummySlave)
|
||||
bus_switch.io.master <> cpu.io.axi4_channels
|
||||
bus_switch.io.address := cpu.io.bus_address
|
||||
for (i <- 0 until Parameters.SlaveDeviceCount) {
|
||||
bus_switch.io.slaves(i) <> dummy.io.channels
|
||||
}
|
||||
rom_loader.io.load_address := ProgramCounter.EntryAddress
|
||||
rom_loader.io.rom_data := instruction_rom.io.data
|
||||
rom_loader.io.load_start := false.B
|
||||
instruction_rom.io.address := rom_loader.io.rom_address
|
||||
cpu.io.stall_flag_bus := true.B
|
||||
cpu.io.instruction_valid := false.B
|
||||
bus_switch.io.slaves(0) <> mem.io.channels
|
||||
rom_loader.io.channels <> dummy.io.channels
|
||||
switch(boot_state) {
|
||||
is(BootStates.Init) {
|
||||
rom_loader.io.load_start := true.B
|
||||
boot_state := BootStates.Loading
|
||||
rom_loader.io.channels <> mem.io.channels
|
||||
}
|
||||
is(BootStates.Loading) {
|
||||
rom_loader.io.load_start := false.B
|
||||
rom_loader.io.channels <> mem.io.channels
|
||||
when(rom_loader.io.load_finished) {
|
||||
boot_state := BootStates.Finished
|
||||
}
|
||||
}
|
||||
is(BootStates.Finished) {
|
||||
rom_loader.io.load_start := false.B
|
||||
cpu.io.stall_flag_bus := false.B
|
||||
cpu.io.instruction_valid := true.B
|
||||
}
|
||||
}
|
||||
bus_switch.io.slaves(4) <> timer.io.channels
|
||||
|
||||
mem.io.debug_read_address := io.mem_debug_read_address
|
||||
cpu.io.debug_read_address := io.regs_debug_read_address
|
||||
io.regs_debug_read_data := cpu.io.debug_read_data
|
||||
io.mem_debug_read_data := mem.io.debug_read_data
|
||||
|
||||
cpu.io.interrupt_flag := io.interrupt
|
||||
}
|
||||
|
||||
|
||||
class FibonacciTest extends AnyFlatSpec with ChiselScalatestTester {
|
||||
behavior of "CPU"
|
||||
it should "calculate recursively fibonacci(10)" in {
|
||||
test(new TestTopModule("fibonacci.asmbin")).withAnnotations(TestAnnotations.annos) { c =>
|
||||
c.io.interrupt.poke(0.U)
|
||||
for (i <- 1 to 50) {
|
||||
c.clock.step(1000)
|
||||
c.io.mem_debug_read_address.poke((i * 4).U) // Avoid timeout
|
||||
}
|
||||
|
||||
c.io.mem_debug_read_address.poke(4.U)
|
||||
c.clock.step()
|
||||
c.io.mem_debug_read_data.expect(55.U)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class QuicksortTest extends AnyFlatSpec with ChiselScalatestTester {
|
||||
behavior of "CPU"
|
||||
it should "quicksort 10 numbers" in {
|
||||
test(new TestTopModule("quicksort.asmbin")).withAnnotations(TestAnnotations.annos) { c =>
|
||||
c.io.interrupt.poke(0.U)
|
||||
for (i <- 1 to 50) {
|
||||
c.clock.step(1000)
|
||||
c.io.mem_debug_read_address.poke((i * 4).U) // Avoid timeout
|
||||
}
|
||||
for (i <- 1 to 10) {
|
||||
c.io.mem_debug_read_address.poke((4 * i).U)
|
||||
c.clock.step()
|
||||
c.io.mem_debug_read_data.expect((i - 1).U)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MMIOTest extends AnyFlatSpec with ChiselScalatestTester {
|
||||
behavior of "CPU"
|
||||
it should "read and write timer register" in {
|
||||
test(new TestTopModule("mmio.asmbin")).withAnnotations(TestAnnotations.annos) { c =>
|
||||
c.io.interrupt.poke(0.U)
|
||||
for (i <- 1 to 200) {
|
||||
c.clock.step()
|
||||
c.io.mem_debug_read_address.poke((i * 4).U) // Avoid timeout
|
||||
}
|
||||
c.io.regs_debug_read_address.poke(5.U)
|
||||
c.io.regs_debug_read_data.expect(100000000.U)
|
||||
c.io.regs_debug_read_address.poke(6.U)
|
||||
c.io.regs_debug_read_data.expect(0xBEEF.U)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ByteAccessTest extends AnyFlatSpec with ChiselScalatestTester {
|
||||
behavior of "CPU"
|
||||
it should "store and load single byte" in {
|
||||
test(new TestTopModule("sb.asmbin")).withAnnotations(TestAnnotations.annos) { c =>
|
||||
c.io.interrupt.poke(0.U)
|
||||
for (i <- 1 to 500) {
|
||||
c.clock.step()
|
||||
c.io.mem_debug_read_address.poke((i * 4).U) // Avoid timeout
|
||||
}
|
||||
c.io.regs_debug_read_address.poke(5.U)
|
||||
c.io.regs_debug_read_data.expect(0xDEADBEEFL.U)
|
||||
c.io.regs_debug_read_address.poke(6.U)
|
||||
c.io.regs_debug_read_data.expect(0xEF.U)
|
||||
c.io.regs_debug_read_address.poke(1.U)
|
||||
c.io.regs_debug_read_data.expect(0x15EF.U)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright 2021 Howard Lau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package riscv.threestage
|
||||
|
||||
import chisel3._
|
||||
import chiseltest._
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import riscv.TestAnnotations
|
||||
import riscv.core.threestage.RegisterFile
|
||||
|
||||
class RegisterFileTest extends AnyFlatSpec with ChiselScalatestTester {
|
||||
behavior of "Register File"
|
||||
it should "read the written content" in {
|
||||
test(new RegisterFile).withAnnotations(TestAnnotations.annos) { c =>
|
||||
timescope {
|
||||
c.io.write_enable.poke(true.B)
|
||||
c.io.write_address.poke(1.U)
|
||||
c.io.write_data.poke(0xDEADBEEFL.U)
|
||||
c.clock.step()
|
||||
}
|
||||
c.io.read_address1.poke(1.U)
|
||||
c.io.read_data1.expect(0xDEADBEEFL.U)
|
||||
}
|
||||
}
|
||||
|
||||
it should "x0 always be zero" in {
|
||||
test(new RegisterFile).withAnnotations(TestAnnotations.annos) { c =>
|
||||
timescope {
|
||||
c.io.write_enable.poke(true.B)
|
||||
c.io.write_address.poke(0.U)
|
||||
c.io.write_data.poke(0xDEADBEEFL.U)
|
||||
c.clock.step()
|
||||
}
|
||||
c.io.read_address1.poke(0.U)
|
||||
c.io.read_data1.expect(0.U)
|
||||
}
|
||||
}
|
||||
|
||||
it should "read the writing content" in {
|
||||
test(new RegisterFile).withAnnotations(TestAnnotations.annos) { c =>
|
||||
timescope {
|
||||
c.io.read_address1.poke(2.U)
|
||||
c.io.read_data1.expect(0.U)
|
||||
c.io.write_enable.poke(true.B)
|
||||
c.io.write_address.poke(2.U)
|
||||
c.io.write_data.poke(0xDEADBEEFL.U)
|
||||
c.io.read_address1.poke(2.U)
|
||||
c.io.read_data1.expect(0xDEADBEEFL.U)
|
||||
c.clock.step()
|
||||
}
|
||||
c.io.read_address1.poke(2.U)
|
||||
c.io.read_data1.expect(0xDEADBEEFL.U)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
35
mini-yatcpu/verilog/basys3/test.v
Normal file
35
mini-yatcpu/verilog/basys3/test.v
Normal file
@@ -0,0 +1,35 @@
|
||||
`timescale 1ns / 1ps
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Company:
|
||||
// Engineer:
|
||||
//
|
||||
// Create Date: 2021/12/17 16:31:05
|
||||
// Design Name:
|
||||
// Module Name: test
|
||||
// Project Name:
|
||||
// Target Devices:
|
||||
// Tool Versions:
|
||||
// Description:
|
||||
//
|
||||
// Dependencies:
|
||||
//
|
||||
// Revision:
|
||||
// Revision 0.01 - File Created
|
||||
// Additional Comments:
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
module test();
|
||||
reg clock;
|
||||
reg reset;
|
||||
initial begin
|
||||
clock = 0;
|
||||
forever #1 clock = ~clock;
|
||||
end
|
||||
initial begin
|
||||
reset = 1;
|
||||
#2 reset = 0;
|
||||
end
|
||||
Top top(clock, reset);
|
||||
endmodule
|
||||
221
mini-yatcpu/verilog/pynq/TMDS_PLLVR.v
Normal file
221
mini-yatcpu/verilog/pynq/TMDS_PLLVR.v
Normal file
@@ -0,0 +1,221 @@
|
||||
|
||||
// file: TMDS_PLLVR.v
|
||||
//
|
||||
// (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved.
|
||||
//
|
||||
// This file contains confidential and proprietary information
|
||||
// of Xilinx, Inc. and is protected under U.S. and
|
||||
// international copyright and other intellectual property
|
||||
// laws.
|
||||
//
|
||||
// DISCLAIMER
|
||||
// This disclaimer is not a license and does not grant any
|
||||
// rights to the materials distributed herewith. Except as
|
||||
// otherwise provided in a valid license issued to you by
|
||||
// Xilinx, and to the maximum extent permitted by applicable
|
||||
// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
|
||||
// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
|
||||
// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
|
||||
// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
|
||||
// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
|
||||
// (2) Xilinx shall not be liable (whether in contract or tort,
|
||||
// including negligence, or under any other theory of
|
||||
// liability) for any loss or damage of any kind or nature
|
||||
// related to, arising under or in connection with these
|
||||
// materials, including for any direct, or any indirect,
|
||||
// special, incidental, or consequential loss or damage
|
||||
// (including loss of data, profits, goodwill, or any type of
|
||||
// loss or damage suffered as a result of any action brought
|
||||
// by a third party) even if such damage or loss was
|
||||
// reasonably foreseeable or Xilinx had been advised of the
|
||||
// possibility of the same.
|
||||
//
|
||||
// CRITICAL APPLICATIONS
|
||||
// Xilinx products are not designed or intended to be fail-
|
||||
// safe, or for use in any application requiring fail-safe
|
||||
// performance, such as life-support or safety devices or
|
||||
// systems, Class III medical devices, nuclear facilities,
|
||||
// applications related to the deployment of airbags, or any
|
||||
// other applications that could lead to death, personal
|
||||
// injury, or severe property or environmental damage
|
||||
// (individually and collectively, "Critical
|
||||
// Applications"). Customer assumes the sole risk and
|
||||
// liability of any use of Xilinx products in Critical
|
||||
// Applications, subject only to applicable laws and
|
||||
// regulations governing limitations on product liability.
|
||||
//
|
||||
// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
|
||||
// PART OF THIS FILE AT ALL TIMES.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// User entered comments
|
||||
//----------------------------------------------------------------------------
|
||||
// None
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Output Output Phase Duty Cycle Pk-to-Pk Phase
|
||||
// Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps)
|
||||
//----------------------------------------------------------------------------
|
||||
// __clkout__250.00000______0.000______50.0______200.536____237.727
|
||||
// _clkoutd__100.00000______0.000______50.0______226.965____237.727
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Input Clock Freq (MHz) Input Jitter (UI)
|
||||
//----------------------------------------------------------------------------
|
||||
// __primary__________25.000____________0.010
|
||||
|
||||
`timescale 1ps/1ps
|
||||
|
||||
(* CORE_GENERATION_INFO = "TMDS_PLLVR,clk_wiz_v6_0_5_0_0,{component_name=TMDS_PLLVR,use_phase_alignment=true,use_min_o_jitter=false,use_max_i_jitter=false,use_dyn_phase_shift=false,use_inclk_switchover=false,use_dyn_reconfig=false,enable_axi=0,feedback_source=FDBK_AUTO,PRIMITIVE=PLL,num_out_clk=2,clkin1_period=40.000,clkin2_period=10.0,use_power_down=false,use_reset=true,use_locked=true,use_inclk_stopped=false,feedback_type=SINGLE,CLOCK_MGR_TYPE=NA,manual_override=true}" *)
|
||||
|
||||
module TMDS_PLLVR
|
||||
(
|
||||
// Clock out ports
|
||||
output clkout,
|
||||
output clkoutd,
|
||||
// Status and control signals
|
||||
input reset,
|
||||
output lock,
|
||||
// Clock in ports
|
||||
input clkin
|
||||
);
|
||||
|
||||
TMDS_PLLVR_clk_wiz inst
|
||||
(
|
||||
// Clock out ports
|
||||
.clkout(clkout),
|
||||
.clkoutd(clkoutd),
|
||||
// Status and control signals
|
||||
.reset(reset),
|
||||
.lock(lock),
|
||||
// Clock in ports
|
||||
.clk_in1(clkin)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
module TMDS_PLLVR_clk_wiz
|
||||
|
||||
(// Clock in ports
|
||||
// Clock out ports
|
||||
output clkout,
|
||||
output clkoutd,
|
||||
// Status and control signals
|
||||
input reset,
|
||||
output lock,
|
||||
input clk_in1
|
||||
);
|
||||
// Input buffering
|
||||
//------------------------------------
|
||||
wire clk_in1_TMDS_PLLVR;
|
||||
wire clk_in2_TMDS_PLLVR;
|
||||
IBUF clkin1_ibufg
|
||||
(.O (clk_in1_TMDS_PLLVR),
|
||||
.I (clk_in1));
|
||||
|
||||
|
||||
|
||||
|
||||
// Clocking PRIMITIVE
|
||||
//------------------------------------
|
||||
|
||||
// Instantiation of the MMCM PRIMITIVE
|
||||
// * Unused inputs are tied off
|
||||
// * Unused outputs are labeled unused
|
||||
|
||||
wire clkout_TMDS_PLLVR;
|
||||
wire clkoutd_TMDS_PLLVR;
|
||||
wire clk_out3_TMDS_PLLVR;
|
||||
wire clk_out4_TMDS_PLLVR;
|
||||
wire clk_out5_TMDS_PLLVR;
|
||||
wire clk_out6_TMDS_PLLVR;
|
||||
wire clk_out7_TMDS_PLLVR;
|
||||
|
||||
wire [15:0] do_unused;
|
||||
wire drdy_unused;
|
||||
wire psdone_unused;
|
||||
wire lock_int;
|
||||
wire clkfbout_TMDS_PLLVR;
|
||||
wire clkfbout_buf_TMDS_PLLVR;
|
||||
wire clkfboutb_unused;
|
||||
wire clkout2_unused;
|
||||
wire clkout3_unused;
|
||||
wire clkout4_unused;
|
||||
wire clkout5_unused;
|
||||
wire clkout6_unused;
|
||||
wire clkfbstopped_unused;
|
||||
wire clkinstopped_unused;
|
||||
wire reset_high;
|
||||
|
||||
PLLE2_ADV
|
||||
#(.BANDWIDTH ("OPTIMIZED"),
|
||||
.COMPENSATION ("ZHOLD"),
|
||||
.STARTUP_WAIT ("FALSE"),
|
||||
.DIVCLK_DIVIDE (1),
|
||||
.CLKFBOUT_MULT (40),
|
||||
.CLKFBOUT_PHASE (0.000),
|
||||
.CLKOUT0_DIVIDE (4),
|
||||
.CLKOUT0_PHASE (0.000),
|
||||
.CLKOUT0_DUTY_CYCLE (0.500),
|
||||
.CLKOUT1_DIVIDE (10),
|
||||
.CLKOUT1_PHASE (0.000),
|
||||
.CLKOUT1_DUTY_CYCLE (0.500),
|
||||
.CLKIN1_PERIOD (40.000))
|
||||
plle2_adv_inst
|
||||
// Output clocks
|
||||
(
|
||||
.CLKFBOUT (clkfbout_TMDS_PLLVR),
|
||||
.CLKOUT0 (clkout_TMDS_PLLVR),
|
||||
.CLKOUT1 (clkoutd_TMDS_PLLVR),
|
||||
.CLKOUT2 (clkout2_unused),
|
||||
.CLKOUT3 (clkout3_unused),
|
||||
.CLKOUT4 (clkout4_unused),
|
||||
.CLKOUT5 (clkout5_unused),
|
||||
// Input clock control
|
||||
.CLKFBIN (clkfbout_buf_TMDS_PLLVR),
|
||||
.CLKIN1 (clk_in1_TMDS_PLLVR),
|
||||
.CLKIN2 (1'b0),
|
||||
// Tied to always select the primary input clock
|
||||
.CLKINSEL (1'b1),
|
||||
// Ports for dynamic reconfiguration
|
||||
.DADDR (7'h0),
|
||||
.DCLK (1'b0),
|
||||
.DEN (1'b0),
|
||||
.DI (16'h0),
|
||||
.DO (do_unused),
|
||||
.DRDY (drdy_unused),
|
||||
.DWE (1'b0),
|
||||
// Other control and status signals
|
||||
.LOCKED (lock_int),
|
||||
.PWRDWN (1'b0),
|
||||
.RST (reset_high));
|
||||
assign reset_high = reset;
|
||||
|
||||
assign lock = lock_int;
|
||||
// Clock Monitor clock assigning
|
||||
//--------------------------------------
|
||||
// Output buffering
|
||||
//-----------------------------------
|
||||
|
||||
BUFG clkf_buf
|
||||
(.O (clkfbout_buf_TMDS_PLLVR),
|
||||
.I (clkfbout_TMDS_PLLVR));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BUFG clkout1_buf
|
||||
(.O (clkout),
|
||||
.I (clkout_TMDS_PLLVR));
|
||||
|
||||
|
||||
BUFG clkout2_buf
|
||||
(.O (clkoutd),
|
||||
.I (clkoutd_TMDS_PLLVR));
|
||||
|
||||
|
||||
|
||||
endmodule
|
||||
136
mini-yatcpu/verilog/pynq/design_1_wrapper.v
Normal file
136
mini-yatcpu/verilog/pynq/design_1_wrapper.v
Normal file
@@ -0,0 +1,136 @@
|
||||
//Copyright 1986-2020 Xilinx, Inc. All Rights Reserved.
|
||||
//--------------------------------------------------------------------------------
|
||||
//Tool Version: Vivado v.2020.1 (win64) Build 2902540 Wed May 27 19:54:49 MDT 2020
|
||||
//Date : Thu Jun 9 10:53:21 2022
|
||||
//Host : DESKTOP-UR8AHA2 running 64-bit major release (build 9200)
|
||||
//Command : generate_target design_1_wrapper.bd
|
||||
//Design : design_1_wrapper
|
||||
//Purpose : IP block netlist
|
||||
//--------------------------------------------------------------------------------
|
||||
`timescale 1 ps / 1 ps
|
||||
|
||||
module design_1_wrapper
|
||||
(DDR_addr,
|
||||
DDR_ba,
|
||||
DDR_cas_n,
|
||||
DDR_ck_n,
|
||||
DDR_ck_p,
|
||||
DDR_cke,
|
||||
DDR_cs_n,
|
||||
DDR_dm,
|
||||
DDR_dq,
|
||||
DDR_dqs_n,
|
||||
DDR_dqs_p,
|
||||
DDR_odt,
|
||||
DDR_ras_n,
|
||||
DDR_reset_n,
|
||||
DDR_we_n,
|
||||
FIXED_IO_ddr_vrn,
|
||||
FIXED_IO_ddr_vrp,
|
||||
FIXED_IO_mio,
|
||||
FIXED_IO_ps_clk,
|
||||
FIXED_IO_ps_porb,
|
||||
FIXED_IO_ps_srstb,
|
||||
io_hdmi_clk_n,
|
||||
io_hdmi_clk_p,
|
||||
io_hdmi_data_n,
|
||||
io_hdmi_data_p,
|
||||
io_hdmi_hpdn,
|
||||
io_led,
|
||||
io_rx,
|
||||
io_tx,
|
||||
reset);
|
||||
inout [14:0]DDR_addr;
|
||||
inout [2:0]DDR_ba;
|
||||
inout DDR_cas_n;
|
||||
inout DDR_ck_n;
|
||||
inout DDR_ck_p;
|
||||
inout DDR_cke;
|
||||
inout DDR_cs_n;
|
||||
inout [3:0]DDR_dm;
|
||||
inout [31:0]DDR_dq;
|
||||
inout [3:0]DDR_dqs_n;
|
||||
inout [3:0]DDR_dqs_p;
|
||||
inout DDR_odt;
|
||||
inout DDR_ras_n;
|
||||
inout DDR_reset_n;
|
||||
inout DDR_we_n;
|
||||
inout FIXED_IO_ddr_vrn;
|
||||
inout FIXED_IO_ddr_vrp;
|
||||
inout [53:0]FIXED_IO_mio;
|
||||
inout FIXED_IO_ps_clk;
|
||||
inout FIXED_IO_ps_porb;
|
||||
inout FIXED_IO_ps_srstb;
|
||||
output io_hdmi_clk_n;
|
||||
output io_hdmi_clk_p;
|
||||
output [2:0]io_hdmi_data_n;
|
||||
output [2:0]io_hdmi_data_p;
|
||||
output io_hdmi_hpdn;
|
||||
output [3:0]io_led;
|
||||
input io_rx;
|
||||
output io_tx;
|
||||
input reset;
|
||||
|
||||
wire [14:0]DDR_addr;
|
||||
wire [2:0]DDR_ba;
|
||||
wire DDR_cas_n;
|
||||
wire DDR_ck_n;
|
||||
wire DDR_ck_p;
|
||||
wire DDR_cke;
|
||||
wire DDR_cs_n;
|
||||
wire [3:0]DDR_dm;
|
||||
wire [31:0]DDR_dq;
|
||||
wire [3:0]DDR_dqs_n;
|
||||
wire [3:0]DDR_dqs_p;
|
||||
wire DDR_odt;
|
||||
wire DDR_ras_n;
|
||||
wire DDR_reset_n;
|
||||
wire DDR_we_n;
|
||||
wire FIXED_IO_ddr_vrn;
|
||||
wire FIXED_IO_ddr_vrp;
|
||||
wire [53:0]FIXED_IO_mio;
|
||||
wire FIXED_IO_ps_clk;
|
||||
wire FIXED_IO_ps_porb;
|
||||
wire FIXED_IO_ps_srstb;
|
||||
wire io_hdmi_clk_n;
|
||||
wire io_hdmi_clk_p;
|
||||
wire [2:0]io_hdmi_data_n;
|
||||
wire [2:0]io_hdmi_data_p;
|
||||
wire io_hdmi_hpdn;
|
||||
wire [3:0]io_led;
|
||||
wire io_rx;
|
||||
wire io_tx;
|
||||
wire reset;
|
||||
|
||||
design_1 design_1_i
|
||||
(.DDR_addr(DDR_addr),
|
||||
.DDR_ba(DDR_ba),
|
||||
.DDR_cas_n(DDR_cas_n),
|
||||
.DDR_ck_n(DDR_ck_n),
|
||||
.DDR_ck_p(DDR_ck_p),
|
||||
.DDR_cke(DDR_cke),
|
||||
.DDR_cs_n(DDR_cs_n),
|
||||
.DDR_dm(DDR_dm),
|
||||
.DDR_dq(DDR_dq),
|
||||
.DDR_dqs_n(DDR_dqs_n),
|
||||
.DDR_dqs_p(DDR_dqs_p),
|
||||
.DDR_odt(DDR_odt),
|
||||
.DDR_ras_n(DDR_ras_n),
|
||||
.DDR_reset_n(DDR_reset_n),
|
||||
.DDR_we_n(DDR_we_n),
|
||||
.FIXED_IO_ddr_vrn(FIXED_IO_ddr_vrn),
|
||||
.FIXED_IO_ddr_vrp(FIXED_IO_ddr_vrp),
|
||||
.FIXED_IO_mio(FIXED_IO_mio),
|
||||
.FIXED_IO_ps_clk(FIXED_IO_ps_clk),
|
||||
.FIXED_IO_ps_porb(FIXED_IO_ps_porb),
|
||||
.FIXED_IO_ps_srstb(FIXED_IO_ps_srstb),
|
||||
.io_hdmi_clk_n(io_hdmi_clk_n),
|
||||
.io_hdmi_clk_p(io_hdmi_clk_p),
|
||||
.io_hdmi_data_n(io_hdmi_data_n),
|
||||
.io_hdmi_data_p(io_hdmi_data_p),
|
||||
.io_hdmi_hpdn(io_hdmi_hpdn),
|
||||
.io_led(io_led),
|
||||
.io_rx(io_rx),
|
||||
.io_tx(io_tx),
|
||||
.reset(reset));
|
||||
endmodule
|
||||
35
mini-yatcpu/verilog/pynq/test.v
Normal file
35
mini-yatcpu/verilog/pynq/test.v
Normal file
@@ -0,0 +1,35 @@
|
||||
`timescale 1ns / 1ps
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Company:
|
||||
// Engineer:
|
||||
//
|
||||
// Create Date: 2021/12/17 16:31:05
|
||||
// Design Name:
|
||||
// Module Name: test
|
||||
// Project Name:
|
||||
// Target Devices:
|
||||
// Tool Versions:
|
||||
// Description:
|
||||
//
|
||||
// Dependencies:
|
||||
//
|
||||
// Revision:
|
||||
// Revision 0.01 - File Created
|
||||
// Additional Comments:
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
module test();
|
||||
reg clock;
|
||||
reg reset;
|
||||
initial begin
|
||||
clock = 0;
|
||||
forever #1 clock = ~clock;
|
||||
end
|
||||
initial begin
|
||||
reset = 1;
|
||||
#2 reset = 0;
|
||||
end
|
||||
Top top(clock, reset);
|
||||
endmodule
|
||||
2102
mini-yatcpu/verilog/say_goodbye.asmbin.txt
Normal file
2102
mini-yatcpu/verilog/say_goodbye.asmbin.txt
Normal file
File diff suppressed because it is too large
Load Diff
230
mini-yatcpu/verilog/verilator/sim_main.cpp
Normal file
230
mini-yatcpu/verilog/verilator/sim_main.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
#include <verilated.h>
|
||||
#include <verilated_vcd_c.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "VTop.h" // From Verilating "top.v"
|
||||
|
||||
class Memory {
|
||||
std::vector<uint32_t> memory;
|
||||
|
||||
public:
|
||||
Memory(size_t size) : memory(size, 0) {}
|
||||
uint32_t read(size_t address) {
|
||||
address = address / 4;
|
||||
if (address >= memory.size()) {
|
||||
printf("invalid read address 0x%08x\n", address * 4);
|
||||
return 0;
|
||||
}
|
||||
return memory[address];
|
||||
}
|
||||
|
||||
void write(size_t address, uint32_t value, bool write_strobe[4]) {
|
||||
address = address / 4;
|
||||
uint32_t write_mask = 0;
|
||||
if (write_strobe[0]) write_mask |= 0x000000FF;
|
||||
if (write_strobe[1]) write_mask |= 0x0000FF00;
|
||||
if (write_strobe[2]) write_mask |= 0x00FF0000;
|
||||
if (write_strobe[3]) write_mask |= 0xFF000000;
|
||||
if (address >= memory.size()) {
|
||||
printf("invalid write address 0x%08x\n", address * 4);
|
||||
return;
|
||||
}
|
||||
memory[address] = (memory[address] & ~write_mask) | (value & write_mask);
|
||||
}
|
||||
|
||||
void load_binary(std::string const& filename, size_t load_address = 0x1000) {
|
||||
std::ifstream file(filename, std::ios::binary);
|
||||
if (!file) {
|
||||
throw std::runtime_error("Could not open file " + filename);
|
||||
}
|
||||
file.seekg(0, std::ios::end);
|
||||
size_t size = file.tellg();
|
||||
if (load_address + size > memory.size() * 4) {
|
||||
throw std::runtime_error("File " + filename + " is too large (File is " +
|
||||
std::to_string(size) + " bytes. Memory is " +
|
||||
std::to_string(memory.size() * 4 - load_address) + " bytes.)");
|
||||
}
|
||||
file.seekg(0, std::ios::beg);
|
||||
for (int i = 0; i < size / 4; ++i) {
|
||||
file.read(reinterpret_cast<char*>(&memory[i + load_address / 4]),
|
||||
sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class VCDTracer {
|
||||
VerilatedVcdC* tfp = nullptr;
|
||||
|
||||
public:
|
||||
void enable(std::string const& filename, VTop& top) {
|
||||
Verilated::traceEverOn(true);
|
||||
tfp = new VerilatedVcdC;
|
||||
top.trace(tfp, 99);
|
||||
tfp->open(filename.c_str());
|
||||
tfp->set_time_resolution("1ps");
|
||||
tfp->set_time_unit("1ns");
|
||||
if (!tfp->isOpen()) {
|
||||
throw std::runtime_error("Failed to open VCD dump file " + filename);
|
||||
}
|
||||
}
|
||||
|
||||
void dump(vluint64_t time) {
|
||||
if (tfp) {
|
||||
tfp->dump(time);
|
||||
}
|
||||
}
|
||||
|
||||
~VCDTracer() {
|
||||
if (tfp) {
|
||||
tfp->close();
|
||||
delete tfp;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
uint32_t parse_number(std::string const& str) {
|
||||
if (str.size() > 2) {
|
||||
auto&& prefix = str.substr(0, 2);
|
||||
if (prefix == "0x" || prefix == "0X") {
|
||||
return std::stoul(str.substr(2), nullptr, 16);
|
||||
}
|
||||
}
|
||||
return std::stoul(str);
|
||||
}
|
||||
|
||||
class Simulator {
|
||||
vluint64_t main_time = 0;
|
||||
vluint64_t max_sim_time = 10000;
|
||||
uint32_t halt_address = 0;
|
||||
size_t memory_words = 1024 * 1024; // 4MB
|
||||
bool dump_vcd = false;
|
||||
std::unique_ptr<VTop> top;
|
||||
std::unique_ptr<VCDTracer> vcd_tracer;
|
||||
std::unique_ptr<Memory> memory;
|
||||
bool dump_signature = false;
|
||||
unsigned long signature_begin, signature_end;
|
||||
std::string signature_filename;
|
||||
std::string instruction_filename;
|
||||
|
||||
public:
|
||||
void parse_args(std::vector<std::string> const& args) {
|
||||
if (auto it = std::find(args.begin(), args.end(), "-halt");
|
||||
it != args.end()) {
|
||||
halt_address = parse_number(*(it + 1));
|
||||
}
|
||||
|
||||
if (auto it = std::find(args.begin(), args.end(), "-memory");
|
||||
it != args.end()) {
|
||||
memory_words = std::stoul(*(it + 1));
|
||||
}
|
||||
|
||||
if (auto it = std::find(args.begin(), args.end(), "-time");
|
||||
it != args.end()) {
|
||||
max_sim_time = std::stoul(*(it + 1));
|
||||
}
|
||||
|
||||
if (auto it = std::find(args.begin(), args.end(), "-vcd");
|
||||
it != args.end()) {
|
||||
vcd_tracer->enable(*(it + 1), *top);
|
||||
}
|
||||
|
||||
if (auto it = std::find(args.begin(), args.end(), "-signature");
|
||||
it != args.end()) {
|
||||
dump_signature = true;
|
||||
signature_begin = parse_number(*(it + 1));
|
||||
signature_end = parse_number(*(it + 2));
|
||||
signature_filename = *(it + 3);
|
||||
}
|
||||
|
||||
if (auto it = std::find(args.begin(), args.end(), "-instruction");
|
||||
it != args.end()) {
|
||||
instruction_filename = *(it + 1);
|
||||
}
|
||||
}
|
||||
|
||||
Simulator(std::vector<std::string> const& args)
|
||||
: top(std::make_unique<VTop>()),
|
||||
vcd_tracer(std::make_unique<VCDTracer>()) {
|
||||
parse_args(args);
|
||||
memory = std::make_unique<Memory>(memory_words);
|
||||
if (!instruction_filename.empty()) {
|
||||
memory->load_binary(instruction_filename);
|
||||
}
|
||||
}
|
||||
|
||||
void run() {
|
||||
top->reset = 1;
|
||||
top->clock = 0;
|
||||
top->io_mem_slave_read_valid = true;
|
||||
top->eval();
|
||||
vcd_tracer->dump(main_time);
|
||||
uint32_t memory_read_word = 0;
|
||||
bool memory_write_strobe[4] = {false};
|
||||
bool uart_debounce = false;
|
||||
while (main_time < max_sim_time && !Verilated::gotFinish()) {
|
||||
++main_time;
|
||||
if (main_time > 2) {
|
||||
top->reset = 0;
|
||||
}
|
||||
top->io_mem_slave_read_data = memory_read_word;
|
||||
top->clock = !top->clock;
|
||||
top->eval();
|
||||
if (top->io_uart_slave_write) {
|
||||
if (uart_debounce && top->clock) {
|
||||
std::cout << (char)top->io_uart_slave_write_data << std::flush;
|
||||
}
|
||||
if (!uart_debounce && top->clock) {
|
||||
uart_debounce = true;
|
||||
}
|
||||
} else {
|
||||
uart_debounce = false;
|
||||
}
|
||||
if (top->io_mem_slave_read) {
|
||||
memory_read_word = memory->read(top->io_mem_slave_address);
|
||||
}
|
||||
if (top->io_mem_slave_write) {
|
||||
memory_write_strobe[0] = top->io_mem_slave_write_strobe_0;
|
||||
memory_write_strobe[1] = top->io_mem_slave_write_strobe_1;
|
||||
memory_write_strobe[2] = top->io_mem_slave_write_strobe_2;
|
||||
memory_write_strobe[3] = top->io_mem_slave_write_strobe_3;
|
||||
memory->write(top->io_mem_slave_address, top->io_mem_slave_write_data,
|
||||
memory_write_strobe);
|
||||
}
|
||||
vcd_tracer->dump(main_time);
|
||||
if (halt_address) {
|
||||
if (memory->read(halt_address) == 0xBABECAFE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dump_signature) {
|
||||
char data[9] = {0};
|
||||
std::ofstream signature_file(signature_filename);
|
||||
for (size_t addr = signature_begin; addr < signature_end; addr += 4) {
|
||||
snprintf(data, 9, "%08x", memory->read(addr));
|
||||
signature_file << data << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~Simulator() {
|
||||
if (top) {
|
||||
top->final();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
std::vector<std::string> args(argv, argv + argc);
|
||||
Simulator simulator(args);
|
||||
simulator.run();
|
||||
return 0;
|
||||
}
|
||||
498
mini-yatcpu/verilog/z710/Top.anno.json
Normal file
498
mini-yatcpu/verilog/z710/Top.anno.json
Normal file
@@ -0,0 +1,498 @@
|
||||
[
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|AXI4LiteSlave",
|
||||
"duplicate":"~Top|Top/uart:Uart/slave:AXI4LiteSlave",
|
||||
"index":0.0
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/if2id:IF2ID/instruction:PipelineRegister",
|
||||
"index":0.11842105263157894
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_1",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/if2id:IF2ID/instruction_address:PipelineRegister_1",
|
||||
"index":0.13157894736842105
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_2",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/if2id:IF2ID/interrupt_flag:PipelineRegister_2",
|
||||
"index":0.14473684210526316
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_3",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/id2ex:ID2EX/instruction:PipelineRegister",
|
||||
"index":0.18421052631578946
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_4",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/id2ex:ID2EX/instruction_address:PipelineRegister_1",
|
||||
"index":0.19736842105263158
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_5",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/id2ex:ID2EX/regs_write_enable:PipelineRegister_5",
|
||||
"index":0.21052631578947367
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_6",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/id2ex:ID2EX/regs_write_address:PipelineRegister_6",
|
||||
"index":0.2236842105263158
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_7",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/id2ex:ID2EX/regs_write_source:PipelineRegister_7",
|
||||
"index":0.23684210526315788
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_8",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/id2ex:ID2EX/reg1_data:PipelineRegister_2",
|
||||
"index":0.25
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_9",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/id2ex:ID2EX/reg2_data:PipelineRegister_2",
|
||||
"index":0.2631578947368421
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_10",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/id2ex:ID2EX/immediate:PipelineRegister_2",
|
||||
"index":0.27631578947368424
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_11",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/id2ex:ID2EX/aluop1_source:PipelineRegister_5",
|
||||
"index":0.2894736842105263
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_12",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/id2ex:ID2EX/aluop2_source:PipelineRegister_5",
|
||||
"index":0.3026315789473684
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_13",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/id2ex:ID2EX/csr_write_enable:PipelineRegister_5",
|
||||
"index":0.3157894736842105
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_15",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/id2ex:ID2EX/memory_read_enable:PipelineRegister_5",
|
||||
"index":0.34210526315789475
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_16",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/id2ex:ID2EX/memory_write_enable:PipelineRegister_5",
|
||||
"index":0.35526315789473684
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_17",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/id2ex:ID2EX/csr_read_data:PipelineRegister_2",
|
||||
"index":0.3684210526315789
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_18",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/ex2mem:EX2MEM/regs_write_enable:PipelineRegister_5",
|
||||
"index":0.4342105263157895
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_19",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/ex2mem:EX2MEM/regs_write_source:PipelineRegister_7",
|
||||
"index":0.4473684210526316
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_20",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/ex2mem:EX2MEM/regs_write_address:PipelineRegister_6",
|
||||
"index":0.4605263157894737
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_21",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/ex2mem:EX2MEM/instruction_address:PipelineRegister_2",
|
||||
"index":0.47368421052631576
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_22",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/ex2mem:EX2MEM/instruction:PipelineRegister_2",
|
||||
"index":0.4868421052631579
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_23",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/ex2mem:EX2MEM/reg1_data:PipelineRegister_2",
|
||||
"index":0.5
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_24",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/ex2mem:EX2MEM/reg2_data:PipelineRegister_2",
|
||||
"index":0.5131578947368421
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_25",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/ex2mem:EX2MEM/alu_result:PipelineRegister_2",
|
||||
"index":0.5263157894736842
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_26",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/ex2mem:EX2MEM/memory_read_enable:PipelineRegister_5",
|
||||
"index":0.5394736842105263
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_27",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/ex2mem:EX2MEM/memory_write_enable:PipelineRegister_5",
|
||||
"index":0.5526315789473685
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_28",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/ex2mem:EX2MEM/csr_read_data:PipelineRegister_2",
|
||||
"index":0.5657894736842105
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_29",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/mem2wb:MEM2WB/alu_result:PipelineRegister_2",
|
||||
"index":0.6052631578947368
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_30",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/mem2wb:MEM2WB/memory_read_data:PipelineRegister_2",
|
||||
"index":0.618421052631579
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_31",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/mem2wb:MEM2WB/regs_write_enable:PipelineRegister_5",
|
||||
"index":0.631578947368421
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_32",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/mem2wb:MEM2WB/regs_write_source:PipelineRegister_7",
|
||||
"index":0.6447368421052632
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_33",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/mem2wb:MEM2WB/regs_write_address:PipelineRegister_6",
|
||||
"index":0.6578947368421053
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_34",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/mem2wb:MEM2WB/instruction_address:PipelineRegister_2",
|
||||
"index":0.6710526315789473
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|PipelineRegister_35",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/mem2wb:MEM2WB/csr_read_data:PipelineRegister_2",
|
||||
"index":0.6842105263157895
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|AXI4LiteMaster",
|
||||
"duplicate":"~Top|Top/cpu:CPU_1/cpu:CPU/axi4_master:AXI4LiteMaster",
|
||||
"index":0.7631578947368421
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|AXI4LiteSlave_1",
|
||||
"duplicate":"~Top|Top/mem:Memory/slave:AXI4LiteSlave_1",
|
||||
"index":0.8289473684210527
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|AXI4LiteSlave_2",
|
||||
"duplicate":"~Top|Top/timer:Timer/slave:AXI4LiteSlave",
|
||||
"index":0.8552631578947368
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|AXI4LiteSlave_3",
|
||||
"duplicate":"~Top|Top/dummy:DummySlave/slave:AXI4LiteSlave_1",
|
||||
"index":0.881578947368421
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|AXI4LiteMaster_1",
|
||||
"duplicate":"~Top|Top/bus_switch:BusSwitch/dummy:DummyMaster/master:AXI4LiteMaster",
|
||||
"index":0.9210526315789473
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.DedupedResult",
|
||||
"original":"~Top|AXI4LiteMaster_2",
|
||||
"duplicate":"~Top|Top/rom_loader:ROMLoader/master:AXI4LiteMaster",
|
||||
"index":0.9736842105263158
|
||||
},
|
||||
{
|
||||
"class":"firrtl.EmitCircuitAnnotation",
|
||||
"emitter":"firrtl.VerilogEmitter"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.AXI4LiteMaster.state",
|
||||
"enumTypeName":"bus.AXI4LiteStates"
|
||||
},
|
||||
{
|
||||
"class":"firrtl.annotations.MemorySynthInit$"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.AXI4LiteSlave_1.state",
|
||||
"enumTypeName":"bus.AXI4LiteStates"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.AXI4LiteSlave.state",
|
||||
"enumTypeName":"bus.AXI4LiteStates"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumDefAnnotation",
|
||||
"typeName":"riscv.core.fivestage.MEMAccessState",
|
||||
"definition":{
|
||||
"if_address_translate":1,
|
||||
"if_access":4,
|
||||
"idle":0,
|
||||
"mem_address_translate":2,
|
||||
"mem_access":3
|
||||
}
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.CPU.mem_access_state",
|
||||
"enumTypeName":"riscv.core.fivestage.MEMAccessState"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumDefAnnotation",
|
||||
"typeName":"riscv.core.fivestage.BUSGranted",
|
||||
"definition":{
|
||||
"mmu_if_granted":4,
|
||||
"if_granted":1,
|
||||
"mmu_mem_granted":3,
|
||||
"mem_granted":2,
|
||||
"idle":0
|
||||
}
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.CPU.bus_granted",
|
||||
"enumTypeName":"riscv.core.fivestage.BUSGranted"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumDefAnnotation",
|
||||
"typeName":"riscv.core.fivestage.MMUStates",
|
||||
"definition":{
|
||||
"checkpte1":2,
|
||||
"gotPhyicalAddress":6,
|
||||
"setADbit":5,
|
||||
"idle":0,
|
||||
"checkpte0":4,
|
||||
"level1":1,
|
||||
"level0":3
|
||||
}
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.MMU.state",
|
||||
"enumTypeName":"riscv.core.fivestage.MMUStates"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumDefAnnotation",
|
||||
"typeName":"riscv.core.fivestage.MemoryAccessStates",
|
||||
"definition":{
|
||||
"Idle":0,
|
||||
"Read":1,
|
||||
"Write":2,
|
||||
"ReadWrite":3
|
||||
}
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.MemoryAccess.mem_access_state",
|
||||
"enumTypeName":"riscv.core.fivestage.MemoryAccessStates"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.ALUControl._io_alu_funct_T_33",
|
||||
"enumTypeName":"riscv.core.fivestage.ALUFunctions"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.ALUControl._io_alu_funct_T_31",
|
||||
"enumTypeName":"riscv.core.fivestage.ALUFunctions"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.ALUControl._io_alu_funct_T_29",
|
||||
"enumTypeName":"riscv.core.fivestage.ALUFunctions"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.ALUControl._io_alu_funct_T_27",
|
||||
"enumTypeName":"riscv.core.fivestage.ALUFunctions"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.ALUControl._io_alu_funct_T_25",
|
||||
"enumTypeName":"riscv.core.fivestage.ALUFunctions"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.ALUControl._io_alu_funct_T_23",
|
||||
"enumTypeName":"riscv.core.fivestage.ALUFunctions"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.ALUControl._io_alu_funct_T_21",
|
||||
"enumTypeName":"riscv.core.fivestage.ALUFunctions"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.ALUControl._io_alu_funct_T_17",
|
||||
"enumTypeName":"riscv.core.fivestage.ALUFunctions"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.ALUControl._io_alu_funct_T_15",
|
||||
"enumTypeName":"riscv.core.fivestage.ALUFunctions"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.ALUControl._io_alu_funct_T_13",
|
||||
"enumTypeName":"riscv.core.fivestage.ALUFunctions"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.ALUControl._io_alu_funct_T_11",
|
||||
"enumTypeName":"riscv.core.fivestage.ALUFunctions"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.ALUControl._io_alu_funct_T_9",
|
||||
"enumTypeName":"riscv.core.fivestage.ALUFunctions"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.ALUControl._io_alu_funct_T_7",
|
||||
"enumTypeName":"riscv.core.fivestage.ALUFunctions"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.ALUControl._io_alu_funct_T_5",
|
||||
"enumTypeName":"riscv.core.fivestage.ALUFunctions"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.ALUControl._io_alu_funct_T_3",
|
||||
"enumTypeName":"riscv.core.fivestage.ALUFunctions"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.ALUControl._io_alu_funct_T_1",
|
||||
"enumTypeName":"riscv.core.fivestage.ALUFunctions"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.ALUControl.io_alu_funct",
|
||||
"enumTypeName":"riscv.core.fivestage.ALUFunctions"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumDefAnnotation",
|
||||
"typeName":"riscv.core.fivestage.ALUFunctions",
|
||||
"definition":{
|
||||
"sll":3,
|
||||
"sra":9,
|
||||
"or":6,
|
||||
"xor":5,
|
||||
"slt":4,
|
||||
"sub":2,
|
||||
"add":1,
|
||||
"sltu":10,
|
||||
"and":7,
|
||||
"srl":8,
|
||||
"zero":0
|
||||
}
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.ALU.io_func",
|
||||
"enumTypeName":"riscv.core.fivestage.ALUFunctions"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumDefAnnotation",
|
||||
"typeName":"riscv.core.fivestage.IFAccessStates",
|
||||
"definition":{
|
||||
"idle":0,
|
||||
"read":1
|
||||
}
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.InstructionFetch.state",
|
||||
"enumTypeName":"riscv.core.fivestage.IFAccessStates"
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumDefAnnotation",
|
||||
"typeName":"bus.AXI4LiteStates",
|
||||
"definition":{
|
||||
"ReadData":2,
|
||||
"WriteAddr":3,
|
||||
"WriteResp":5,
|
||||
"Idle":0,
|
||||
"WriteData":4,
|
||||
"ReadAddr":1
|
||||
}
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumDefAnnotation",
|
||||
"typeName":"board.z710.BootStates",
|
||||
"definition":{
|
||||
"Init":0,
|
||||
"Loading":1,
|
||||
"BusWait":2,
|
||||
"Finished":3
|
||||
}
|
||||
},
|
||||
{
|
||||
"class":"chisel3.experimental.EnumAnnotations$EnumComponentAnnotation",
|
||||
"target":"Top.Top.boot_state",
|
||||
"enumTypeName":"board.z710.BootStates"
|
||||
},
|
||||
{
|
||||
"class":"firrtl.transforms.BlackBoxTargetDirAnno",
|
||||
"targetDir":"verilog/z710"
|
||||
},
|
||||
{
|
||||
"class":"firrtl.annotations.MemoryFileInlineAnnotation",
|
||||
"target":"~Top|InstructionROM>mem",
|
||||
"filename":"/workspaces/2023-fall-yatcpu-repo/mini-yatcpu/verilog/say_goodbye.asmbin.txt",
|
||||
"hexOrBinary":"h"
|
||||
}
|
||||
]
|
||||
4250
mini-yatcpu/verilog/z710/Top.fir
Normal file
4250
mini-yatcpu/verilog/z710/Top.fir
Normal file
File diff suppressed because it is too large
Load Diff
7795
mini-yatcpu/verilog/z710/Top.v
Normal file
7795
mini-yatcpu/verilog/z710/Top.v
Normal file
File diff suppressed because it is too large
Load Diff
32
mini-yatcpu/verilog/z710/Top_reset.v
Normal file
32
mini-yatcpu/verilog/z710/Top_reset.v
Normal file
@@ -0,0 +1,32 @@
|
||||
`timescale 1ns / 1ps
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Company:
|
||||
// Engineer:
|
||||
//
|
||||
// Create Date: 2023/12/01 16:32:40
|
||||
// Design Name:
|
||||
// Module Name: Top_reset
|
||||
// Project Name:
|
||||
// Target Devices:
|
||||
// Tool Versions:
|
||||
// Description:
|
||||
//
|
||||
// Dependencies:
|
||||
//
|
||||
// Revision:
|
||||
// Revision 0.01 - File Created
|
||||
// Additional Comments:
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
module Top_reset(
|
||||
input reset
|
||||
);
|
||||
initial begin
|
||||
reset = 1;
|
||||
#25 reset = 0;
|
||||
end
|
||||
|
||||
|
||||
endmodule
|
||||
29
mini-yatcpu/verilog/z710/clock_control.v
Normal file
29
mini-yatcpu/verilog/z710/clock_control.v
Normal file
@@ -0,0 +1,29 @@
|
||||
`timescale 1ns / 1ps
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Company:
|
||||
// Engineer:
|
||||
//
|
||||
// Create Date: 2023/11/29 15:52:55
|
||||
// Design Name:
|
||||
// Module Name: clock_control
|
||||
// Project Name:
|
||||
// Target Devices:
|
||||
// Tool Versions:
|
||||
// Description:
|
||||
//
|
||||
// Dependencies:
|
||||
//
|
||||
// Revision:
|
||||
// Revision 0.01 - File Created
|
||||
// Additional Comments:
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
module clock_control(
|
||||
input clk_in,
|
||||
input enable_clk,
|
||||
output clk_out
|
||||
);
|
||||
assign clk_out = clk_in & enable_clk;
|
||||
endmodule
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user