add mini-yatcpu

This commit is contained in:
TOKISAKIX\21168
2023-12-12 11:03:06 +08:00
parent fb1bf9d3f4
commit 73df6caf1c
133 changed files with 29085 additions and 4 deletions

View File

@@ -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 文件**
@@ -114,5 +119,3 @@
- [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 ~)

353
mini-yatcpu/.gitignore vendored Normal file
View 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
View 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
View 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),
)

View File

@@ -0,0 +1 @@
sbt.version = 1.9.6

View File

@@ -0,0 +1 @@
logLevel := Level.Warn

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View 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
}

View 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 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
}

View 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
)
)
}

View 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)
)
)
}

View 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)))
}

View 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)))
}

View 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)))
}

View 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
)
}

View 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
}
}
}
}

View 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)
}

View 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)
}

View 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)
}

View 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
}

View 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
}

View 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)
}
}

View 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())
})
}
//-----------------------------------------

View 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)
}
}

View File

@@ -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))
})
}

View 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
}

View 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)
}

View 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
}

View 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 {
})
}

View 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
}
}

View 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
}
}

View 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
}

View 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
}

View 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())
}

View 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
}
}

View 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)))
}

View 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
}
}
}

View File

@@ -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
}
}
}

View 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
}

View 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
}

View 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
)
}

View 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 {
})
}

View File

@@ -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
}

View 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
}

View File

@@ -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)),
))
}

View File

@@ -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
}
}

View 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
}

View 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
}

View File

@@ -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
)
}

View File

@@ -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
}

View 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
}

View 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
}
}
}
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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
)
)
}

View File

@@ -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)
)
)
}

View 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
}
}
}

View File

@@ -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
}
}
}

View 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
}

View 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
}

View 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
)
}

View 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 {
})
}

View File

@@ -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,
)
)
}

View 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
}
}

View 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
}

View 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
}

View File

@@ -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()
}
}

View 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.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
}

View File

@@ -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
}

View File

@@ -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
)
)
}

View 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 {
})
}

View File

@@ -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))
}

View 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
}
}
}
}

View 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)
}
}
}

View 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
}

View 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)
}
}
}

View 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.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)
}
}
}

View 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)
}
}
}

View 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.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)
}
}
}

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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;
}

View 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"
}
]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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

View 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