mirror of
https://github.com/handsomezhuzhu/2025-yatcpu.git
synced 2026-02-20 20:10:14 +00:00
lab2打包
This commit is contained in:
@@ -27,6 +27,7 @@ class Timer extends Module {
|
|||||||
val debug_enabled = Output(Bool())
|
val debug_enabled = Output(Bool())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
val count = RegInit(0.U(32.W))
|
val count = RegInit(0.U(32.W))
|
||||||
val limit = RegInit(100000000.U(32.W))
|
val limit = RegInit(100000000.U(32.W))
|
||||||
io.debug_limit := limit
|
io.debug_limit := limit
|
||||||
|
|||||||
BIN
lab2/朱梓涵24325356.rar
Normal file
BIN
lab2/朱梓涵24325356.rar
Normal file
Binary file not shown.
126
lab2/朱梓涵24325356/core/CLINT.scala
Normal file
126
lab2/朱梓涵24325356/core/CLINT.scala
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util._
|
||||||
|
import riscv.Parameters
|
||||||
|
|
||||||
|
object InterruptCode {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class CSRDirectAccessBundle extends Bundle {
|
||||||
|
val mstatus = Input(UInt(Parameters.DataWidth))
|
||||||
|
val mepc = Input(UInt(Parameters.DataWidth))
|
||||||
|
val mcause = Input(UInt(Parameters.DataWidth))
|
||||||
|
val mtvec = Input(UInt(Parameters.DataWidth))
|
||||||
|
|
||||||
|
val mstatus_write_data= Output(UInt(Parameters.DataWidth))
|
||||||
|
val mepc_write_data= Output(UInt(Parameters.DataWidth))
|
||||||
|
val mcause_write_data= Output(UInt(Parameters.DataWidth))
|
||||||
|
|
||||||
|
val direct_write_enable = Output(Bool())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Core Local Interrupt Controller
|
||||||
|
class CLINT extends Module {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
// Interrupt signals from peripherals
|
||||||
|
val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth))
|
||||||
|
|
||||||
|
val instruction = Input(UInt(Parameters.InstructionWidth))
|
||||||
|
val instruction_address = Input(UInt(Parameters.AddrWidth))
|
||||||
|
|
||||||
|
val jump_flag = Input(Bool())
|
||||||
|
val jump_address = Input(UInt(Parameters.AddrWidth))
|
||||||
|
|
||||||
|
val interrupt_handler_address = Output(UInt(Parameters.AddrWidth))
|
||||||
|
val interrupt_assert = Output(Bool())
|
||||||
|
|
||||||
|
val csr_bundle = new CSRDirectAccessBundle
|
||||||
|
})
|
||||||
|
val interrupt_enable = io.csr_bundle.mstatus(3)
|
||||||
|
val instruction_address = Mux(
|
||||||
|
io.jump_flag,
|
||||||
|
io.jump_address,
|
||||||
|
io.instruction_address + 4.U,
|
||||||
|
)
|
||||||
|
//lab2(CLINTCSR)
|
||||||
|
val mstatus = io.csr_bundle.mstatus
|
||||||
|
val mie = mstatus(3)
|
||||||
|
val mpie = mstatus(7)
|
||||||
|
|
||||||
|
when(io.interrupt_flag =/= InterruptCode.None && interrupt_enable) {
|
||||||
|
// 处理硬件中断
|
||||||
|
io.interrupt_assert := true.B
|
||||||
|
io.csr_bundle.direct_write_enable := true.B
|
||||||
|
io.interrupt_handler_address := io.csr_bundle.mtvec // 跳转到中断向量
|
||||||
|
io.csr_bundle.mepc_write_data := instruction_address // 保存下一条指令地址
|
||||||
|
io.csr_bundle.mcause_write_data := Mux(
|
||||||
|
io.interrupt_flag === InterruptCode.Timer0,
|
||||||
|
"h80000007".U(Parameters.DataWidth),
|
||||||
|
"h8000000B".U(Parameters.DataWidth)
|
||||||
|
)
|
||||||
|
val new_mpie = mie << 7
|
||||||
|
io.csr_bundle.mstatus_write_data := (mstatus & (~(1.U << 3)).asUInt) | new_mpie | (3.U << 11)
|
||||||
|
}.elsewhen(io.instruction === InstructionsRet.mret) {
|
||||||
|
// mret
|
||||||
|
io.interrupt_assert := true.B
|
||||||
|
io.csr_bundle.direct_write_enable := true.B
|
||||||
|
io.interrupt_handler_address := io.csr_bundle.mepc // 跳转回 mepc
|
||||||
|
// mstatus 更新: MIE <- MPIE, MPIE <- 1
|
||||||
|
val new_mie = mpie << 3
|
||||||
|
io.csr_bundle.mstatus_write_data := (mstatus & (~(1.U << 7)).asUInt) | new_mie | (1.U << 7) | (3.U << 11)
|
||||||
|
|
||||||
|
// mret 不更新 mepc 和 mcause
|
||||||
|
io.csr_bundle.mepc_write_data := io.csr_bundle.mepc
|
||||||
|
io.csr_bundle.mcause_write_data := io.csr_bundle.mcause
|
||||||
|
}.elsewhen(io.instruction === InstructionsEnv.ecall) {
|
||||||
|
// 处理 ecall
|
||||||
|
io.interrupt_assert := true.B
|
||||||
|
io.csr_bundle.direct_write_enable := true.B
|
||||||
|
io.interrupt_handler_address := io.csr_bundle.mtvec
|
||||||
|
io.csr_bundle.mepc_write_data := instruction_address
|
||||||
|
io.csr_bundle.mcause_write_data := 11.U
|
||||||
|
val new_mpie = mie << 7
|
||||||
|
io.csr_bundle.mstatus_write_data := (mstatus & (~(1.U << 3)).asUInt) | new_mpie | (3.U << 11)
|
||||||
|
}.elsewhen(io.instruction === InstructionsEnv.ebreak) {
|
||||||
|
// 处理 ebreak
|
||||||
|
io.interrupt_assert := true.B
|
||||||
|
io.csr_bundle.direct_write_enable := true.B
|
||||||
|
io.interrupt_handler_address := io.csr_bundle.mtvec
|
||||||
|
io.csr_bundle.mepc_write_data := instruction_address
|
||||||
|
io.csr_bundle.mcause_write_data := 3.U
|
||||||
|
val new_mpie = mie << 7
|
||||||
|
io.csr_bundle.mstatus_write_data := (mstatus & (~(1.U << 3)).asUInt) | new_mpie | (3.U << 11)
|
||||||
|
}.otherwise {
|
||||||
|
|
||||||
|
io.interrupt_assert := false.B
|
||||||
|
io.csr_bundle.direct_write_enable := false.B
|
||||||
|
io.interrupt_handler_address := 0.U
|
||||||
|
|
||||||
|
io.csr_bundle.mstatus_write_data := mstatus
|
||||||
|
io.csr_bundle.mepc_write_data := io.csr_bundle.mepc
|
||||||
|
io.csr_bundle.mcause_write_data := io.csr_bundle.mcause
|
||||||
|
}
|
||||||
|
}
|
||||||
106
lab2/朱梓涵24325356/core/CSR.scala
Normal file
106
lab2/朱梓涵24325356/core/CSR.scala
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util._
|
||||||
|
import riscv.Parameters
|
||||||
|
|
||||||
|
|
||||||
|
object CSRRegister {
|
||||||
|
// Refer to Spec. Vol.II Page 8-10
|
||||||
|
val MSTATUS = 0x300.U(Parameters.CSRRegisterAddrWidth)
|
||||||
|
val MIE = 0x304.U(Parameters.CSRRegisterAddrWidth)
|
||||||
|
val MTVEC = 0x305.U(Parameters.CSRRegisterAddrWidth)
|
||||||
|
val MSCRATCH = 0x340.U(Parameters.CSRRegisterAddrWidth)
|
||||||
|
val MEPC = 0x341.U(Parameters.CSRRegisterAddrWidth)
|
||||||
|
val MCAUSE = 0x342.U(Parameters.CSRRegisterAddrWidth)
|
||||||
|
val CycleL = 0xc00.U(Parameters.CSRRegisterAddrWidth)
|
||||||
|
val CycleH = 0xc80.U(Parameters.CSRRegisterAddrWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
class CSR extends Module {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
val reg_read_address_id = Input(UInt(Parameters.CSRRegisterAddrWidth))
|
||||||
|
val reg_write_enable_id= Input(Bool())
|
||||||
|
val reg_write_address_id = Input(UInt(Parameters.CSRRegisterAddrWidth))
|
||||||
|
val reg_write_data_ex= Input(UInt(Parameters.DataWidth))
|
||||||
|
val debug_reg_read_address = Input(UInt(Parameters.CSRRegisterAddrWidth))
|
||||||
|
|
||||||
|
val debug_reg_read_data = Output(UInt(Parameters.DataWidth))
|
||||||
|
val reg_read_data = Output(UInt(Parameters.DataWidth))
|
||||||
|
|
||||||
|
val clint_access_bundle = Flipped(new CSRDirectAccessBundle)
|
||||||
|
})
|
||||||
|
|
||||||
|
val mstatus = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||||
|
val mie = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||||
|
val mtvec = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||||
|
val mscratch = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||||
|
val mepc = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||||
|
val mcause = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||||
|
val cycles = RegInit(UInt(64.W), 0.U)
|
||||||
|
val regLUT =
|
||||||
|
IndexedSeq(
|
||||||
|
CSRRegister.MSTATUS -> mstatus,
|
||||||
|
CSRRegister.MIE -> mie,
|
||||||
|
CSRRegister.MTVEC -> mtvec,
|
||||||
|
CSRRegister.MSCRATCH -> mscratch,
|
||||||
|
CSRRegister.MEPC -> mepc,
|
||||||
|
CSRRegister.MCAUSE -> mcause,
|
||||||
|
CSRRegister.CycleL -> cycles(31, 0),
|
||||||
|
CSRRegister.CycleH -> cycles(63, 32),
|
||||||
|
)
|
||||||
|
cycles := cycles + 1.U
|
||||||
|
|
||||||
|
// If the pipeline and the CLINT are going to read and write the CSR at the same time, let the pipeline write first.
|
||||||
|
// This is implemented in a single cycle by passing reg_write_data_ex to clint and writing the data from the CLINT to the CSR.
|
||||||
|
io.reg_read_data := MuxLookup(io.reg_read_address_id, 0.U, regLUT)
|
||||||
|
io.debug_reg_read_data := MuxLookup(io.debug_reg_read_address, 0.U,regLUT)
|
||||||
|
|
||||||
|
//lab2(CLINTCSR)
|
||||||
|
val mstatus_next = Mux(io.reg_write_enable_id && io.reg_write_address_id === CSRRegister.MSTATUS, io.reg_write_data_ex, mstatus)
|
||||||
|
val mepc_next = Mux(io.reg_write_enable_id && io.reg_write_address_id === CSRRegister.MEPC, io.reg_write_data_ex, mepc)
|
||||||
|
val mcause_next = Mux(io.reg_write_enable_id && io.reg_write_address_id === CSRRegister.MCAUSE, io.reg_write_data_ex, mcause)
|
||||||
|
val mtvec_next = Mux(io.reg_write_enable_id && io.reg_write_address_id === CSRRegister.MTVEC, io.reg_write_data_ex, mtvec)
|
||||||
|
|
||||||
|
io.clint_access_bundle.mstatus := mstatus_next
|
||||||
|
io.clint_access_bundle.mepc := mepc_next
|
||||||
|
io.clint_access_bundle.mcause := mcause_next
|
||||||
|
io.clint_access_bundle.mtvec := mtvec_next
|
||||||
|
|
||||||
|
when(io.clint_access_bundle.direct_write_enable) {
|
||||||
|
|
||||||
|
mstatus := io.clint_access_bundle.mstatus_write_data
|
||||||
|
mepc := io.clint_access_bundle.mepc_write_data
|
||||||
|
mcause := io.clint_access_bundle.mcause_write_data
|
||||||
|
}.elsewhen(io.reg_write_enable_id) {
|
||||||
|
|
||||||
|
when(io.reg_write_address_id === CSRRegister.MSTATUS) {
|
||||||
|
mstatus := io.reg_write_data_ex
|
||||||
|
}.elsewhen(io.reg_write_address_id === CSRRegister.MEPC) {
|
||||||
|
mepc := io.reg_write_data_ex
|
||||||
|
}.elsewhen(io.reg_write_address_id === CSRRegister.MCAUSE) {
|
||||||
|
mcause := io.reg_write_data_ex
|
||||||
|
}.elsewhen(io.reg_write_address_id === CSRRegister.MTVEC) {
|
||||||
|
mtvec := io.reg_write_data_ex
|
||||||
|
}.elsewhen(io.reg_write_address_id === CSRRegister.MIE) {
|
||||||
|
mie := io.reg_write_data_ex
|
||||||
|
}.elsewhen(io.reg_write_address_id === CSRRegister.MSCRATCH) {
|
||||||
|
mscratch := io.reg_write_data_ex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
93
lab2/朱梓涵24325356/core/Execute.scala
Normal file
93
lab2/朱梓涵24325356/core/Execute.scala
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util.{Cat, MuxLookup}
|
||||||
|
import riscv.Parameters
|
||||||
|
|
||||||
|
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_reg_read_data = Input(UInt(Parameters.DataWidth))
|
||||||
|
|
||||||
|
val mem_alu_result = Output(UInt(Parameters.DataWidth))
|
||||||
|
val csr_reg_write_data = Output(UInt(Parameters.DataWidth))
|
||||||
|
val if_jump_flag = Output(Bool())
|
||||||
|
val if_jump_address = Output(UInt(Parameters.DataWidth))
|
||||||
|
})
|
||||||
|
|
||||||
|
val opcode = io.instruction(6, 0)
|
||||||
|
val funct3 = io.instruction(14, 12)
|
||||||
|
val funct7 = io.instruction(31, 25)
|
||||||
|
|
||||||
|
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,
|
||||||
|
io.reg1_data,
|
||||||
|
)
|
||||||
|
alu.io.op2 := Mux(
|
||||||
|
io.aluop2_source === ALUOp2Source.Immediate,
|
||||||
|
io.immediate,
|
||||||
|
io.reg2_data,
|
||||||
|
)
|
||||||
|
io.if_jump_flag := opcode === Instructions.jal ||
|
||||||
|
(opcode === Instructions.jalr) ||
|
||||||
|
(opcode === InstructionTypes.B) && MuxLookup(
|
||||||
|
funct3,
|
||||||
|
false.B,
|
||||||
|
IndexedSeq(
|
||||||
|
InstructionsTypeB.beq -> (io.reg1_data === io.reg2_data),
|
||||||
|
InstructionsTypeB.bne -> (io.reg1_data =/= io.reg2_data),
|
||||||
|
InstructionsTypeB.blt -> (io.reg1_data.asSInt < io.reg2_data.asSInt),
|
||||||
|
InstructionsTypeB.bge -> (io.reg1_data.asSInt >= io.reg2_data.asSInt),
|
||||||
|
InstructionsTypeB.bltu -> (io.reg1_data.asUInt < io.reg2_data.asUInt),
|
||||||
|
InstructionsTypeB.bgeu -> (io.reg1_data.asUInt >= io.reg2_data.asUInt)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
io.if_jump_address := io.immediate + Mux(opcode === Instructions.jalr, io.reg1_data, io.instruction_address)
|
||||||
|
io.mem_alu_result := alu.io.result
|
||||||
|
|
||||||
|
|
||||||
|
//lab2(CLINTCSR)
|
||||||
|
val uimm = io.instruction(19, 15)
|
||||||
|
io.csr_reg_write_data := MuxLookup(
|
||||||
|
funct3,
|
||||||
|
0.U, // 默认值为0
|
||||||
|
IndexedSeq(
|
||||||
|
|
||||||
|
"b001".U -> io.reg1_data,
|
||||||
|
"b010".U -> (io.csr_reg_read_data | io.reg1_data),
|
||||||
|
"b011".U -> (io.csr_reg_read_data & (~io.reg1_data).asUInt),
|
||||||
|
|
||||||
|
"b101".U -> uimm,
|
||||||
|
"b110".U -> (io.csr_reg_read_data | 8.U),
|
||||||
|
"b111".U -> (io.csr_reg_read_data & io.reg1_data)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
61
lab2/朱梓涵24325356/core/Timer.scala
Normal file
61
lab2/朱梓涵24325356/core/Timer.scala
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// Copyright 2021 Howard Lau
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package peripheral
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util._
|
||||||
|
import riscv.Parameters
|
||||||
|
|
||||||
|
class Timer extends Module {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
val bundle = new RAMBundle
|
||||||
|
val signal_interrupt = Output(Bool())
|
||||||
|
|
||||||
|
val debug_limit = Output(UInt(Parameters.DataWidth))
|
||||||
|
val debug_enabled = Output(Bool())
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
//lab2(CLINTCSR)
|
||||||
|
val address = io.bundle.address
|
||||||
|
io.bundle.read_data := 0.U
|
||||||
|
when(address === 0x4.U) {
|
||||||
|
io.bundle.read_data := limit
|
||||||
|
}.elsewhen(address === 0x8.U) {
|
||||||
|
io.bundle.read_data := enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
when(io.bundle.write_enable) {
|
||||||
|
when(address === 0x4.U) {
|
||||||
|
limit := io.bundle.write_data
|
||||||
|
}.elsewhen(address === 0x8.U) {
|
||||||
|
enabled := io.bundle.write_data(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
when(enabled && count >= limit) {
|
||||||
|
io.signal_interrupt := true.B
|
||||||
|
count := 0.U
|
||||||
|
}.otherwise {
|
||||||
|
io.signal_interrupt := false.B
|
||||||
|
count := count + 1.U
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
lab2/朱梓涵24325356/report.pdf
Normal file
BIN
lab2/朱梓涵24325356/report.pdf
Normal file
Binary file not shown.
54
lab2/朱梓涵24325356/scala/board/basys3/BCD2Segments.scala
Normal file
54
lab2/朱梓涵24325356/scala/board/basys3/BCD2Segments.scala
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2021 Howard Lau
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package board.basys3
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util._
|
||||||
|
|
||||||
|
class BCD2Segments extends Module {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
val bcd = Input(UInt(4.W))
|
||||||
|
val segs = Output(UInt(8.W))
|
||||||
|
})
|
||||||
|
|
||||||
|
val bcd = io.bcd
|
||||||
|
val segs = Wire(UInt(8.W))
|
||||||
|
|
||||||
|
segs := MuxLookup(
|
||||||
|
bcd,
|
||||||
|
0xFF.U,
|
||||||
|
IndexedSeq(
|
||||||
|
0.U -> "b10000001".U,
|
||||||
|
1.U -> "b11001111".U,
|
||||||
|
2.U -> "b10010010".U,
|
||||||
|
3.U -> "b10000110".U,
|
||||||
|
4.U -> "b11001100".U,
|
||||||
|
5.U -> "b10100100".U,
|
||||||
|
6.U -> "b10100000".U,
|
||||||
|
7.U -> "b10001111".U,
|
||||||
|
8.U -> "b10000000".U,
|
||||||
|
9.U -> "b10000100".U,
|
||||||
|
10.U -> "b00001000".U,
|
||||||
|
11.U -> "b01100000".U,
|
||||||
|
12.U -> "b00110001".U,
|
||||||
|
13.U -> "b01000010".U,
|
||||||
|
14.U -> "b00110000".U,
|
||||||
|
15.U -> "b00111000".U,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
io.segs := segs
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
// Copyright 2021 Howard Lau
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package board.basys3
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
|
||||||
|
class OnboardDigitDisplay extends Module {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
val digit_mask = Output(UInt(4.W))
|
||||||
|
})
|
||||||
|
|
||||||
|
val counter = RegInit(UInt(16.W), 0.U)
|
||||||
|
val digit_mask = RegInit(UInt(4.W), "b0111".U)
|
||||||
|
|
||||||
|
counter := counter + 1.U
|
||||||
|
when(counter === 0.U) {
|
||||||
|
digit_mask := (digit_mask << 1.U).asUInt + digit_mask(3)
|
||||||
|
}
|
||||||
|
io.digit_mask := digit_mask
|
||||||
|
}
|
||||||
34
lab2/朱梓涵24325356/scala/board/basys3/SYSULogo.scala
Normal file
34
lab2/朱梓涵24325356/scala/board/basys3/SYSULogo.scala
Normal 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 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
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
42
lab2/朱梓涵24325356/scala/board/basys3/SegmentMux.scala
Normal file
42
lab2/朱梓涵24325356/scala/board/basys3/SegmentMux.scala
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// 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)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
138
lab2/朱梓涵24325356/scala/board/basys3/Top.scala
Normal file
138
lab2/朱梓涵24325356/scala/board/basys3/Top.scala
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
// 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.experimental.ChiselEnum
|
||||||
|
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
|
||||||
|
import chisel3.util._
|
||||||
|
import peripheral.{CharacterDisplay, Dummy, InstructionROM, Memory, ROMLoader, Uart, VGADisplay, Timer}
|
||||||
|
import riscv._
|
||||||
|
import riscv.core.{CPU, ProgramCounter}
|
||||||
|
|
||||||
|
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 mem = Module(new Memory(Parameters.MemorySizeInWords))
|
||||||
|
val vga_display = Module(new VGADisplay)
|
||||||
|
val display = Module(new CharacterDisplay)
|
||||||
|
val timer = Module(new Timer)
|
||||||
|
val uart = Module(new Uart(frequency = 100000000, baudRate = 115200))
|
||||||
|
val dummy = Module(new Dummy)
|
||||||
|
|
||||||
|
display.io.bundle <> dummy.io.bundle
|
||||||
|
mem.io.bundle <> dummy.io.bundle
|
||||||
|
mem.io.debug_read_address := 0.U
|
||||||
|
timer.io.bundle <> dummy.io.bundle
|
||||||
|
uart.io.bundle <> dummy.io.bundle
|
||||||
|
io.tx := uart.io.txd
|
||||||
|
uart.io.rxd := io.rx
|
||||||
|
|
||||||
|
val instruction_rom = Module(new InstructionROM(binaryFilename))
|
||||||
|
val rom_loader = Module(new ROMLoader(instruction_rom.capacity))
|
||||||
|
|
||||||
|
rom_loader.io.rom_data := instruction_rom.io.data
|
||||||
|
rom_loader.io.load_address := Parameters.EntryAddress
|
||||||
|
instruction_rom.io.address := rom_loader.io.rom_address
|
||||||
|
|
||||||
|
val CPU_clkdiv = RegInit(UInt(2.W), 0.U)
|
||||||
|
val CPU_tick = Wire(Bool())
|
||||||
|
val CPU_next = Wire(UInt(2.W))
|
||||||
|
CPU_next := Mux(CPU_clkdiv === 3.U, 0.U, CPU_clkdiv + 1.U)
|
||||||
|
CPU_tick := CPU_clkdiv === 0.U
|
||||||
|
CPU_clkdiv := CPU_next
|
||||||
|
|
||||||
|
withClock(CPU_tick.asClock) {
|
||||||
|
val cpu = Module(new CPU)
|
||||||
|
cpu.io.interrupt_flag := Cat(uart.io.signal_interrupt, timer.io.signal_interrupt)
|
||||||
|
cpu.io.csr_regs_debug_read_address := 0.U
|
||||||
|
cpu.io.regs_debug_read_address := 0.U
|
||||||
|
cpu.io.instruction_valid := rom_loader.io.load_finished
|
||||||
|
mem.io.instruction_address := cpu.io.instruction_address
|
||||||
|
cpu.io.instruction := mem.io.instruction
|
||||||
|
|
||||||
|
when(!rom_loader.io.load_finished) {
|
||||||
|
rom_loader.io.bundle <> mem.io.bundle
|
||||||
|
cpu.io.memory_bundle.read_data := 0.U
|
||||||
|
}.otherwise {
|
||||||
|
rom_loader.io.bundle.read_data := 0.U
|
||||||
|
when(cpu.io.deviceSelect === 4.U) {
|
||||||
|
cpu.io.memory_bundle <> timer.io.bundle
|
||||||
|
}.elsewhen(cpu.io.deviceSelect === 2.U) {
|
||||||
|
cpu.io.memory_bundle <> uart.io.bundle
|
||||||
|
}.elsewhen(cpu.io.deviceSelect === 1.U) {
|
||||||
|
cpu.io.memory_bundle <> display.io.bundle
|
||||||
|
}.otherwise {
|
||||||
|
cpu.io.memory_bundle <> mem.io.bundle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
display.io.x := vga_display.io.x
|
||||||
|
display.io.y := vga_display.io.y
|
||||||
|
|
||||||
|
io.hsync := vga_display.io.hsync
|
||||||
|
io.vsync := vga_display.io.vsync
|
||||||
|
|
||||||
|
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)))
|
||||||
|
}
|
||||||
109
lab2/朱梓涵24325356/scala/board/pynq/Top.scala
Normal file
109
lab2/朱梓涵24325356/scala/board/pynq/Top.scala
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
// 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 chisel3._
|
||||||
|
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
|
||||||
|
import chisel3.util.Cat
|
||||||
|
import peripheral._
|
||||||
|
import riscv.Parameters
|
||||||
|
import riscv.core.{CPU, ProgramCounter}
|
||||||
|
|
||||||
|
class Top extends Module {
|
||||||
|
val binaryFilename = "hello.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 tx = Output(Bool())
|
||||||
|
val rx = Input(Bool())
|
||||||
|
|
||||||
|
val led = Output(UInt(4.W))
|
||||||
|
})
|
||||||
|
val mem = Module(new Memory(Parameters.MemorySizeInWords))
|
||||||
|
val hdmi_display = Module(new HDMIDisplay)
|
||||||
|
val display = Module(new CharacterDisplay)
|
||||||
|
val timer = Module(new Timer)
|
||||||
|
val uart = Module(new Uart(frequency = 125000000, baudRate = 115200))
|
||||||
|
val dummy = Module(new Dummy)
|
||||||
|
|
||||||
|
display.io.bundle <> dummy.io.bundle
|
||||||
|
mem.io.bundle <> dummy.io.bundle
|
||||||
|
mem.io.debug_read_address := 0.U
|
||||||
|
timer.io.bundle <> dummy.io.bundle
|
||||||
|
uart.io.bundle <> dummy.io.bundle
|
||||||
|
io.tx := uart.io.txd
|
||||||
|
uart.io.rxd := io.rx
|
||||||
|
|
||||||
|
val instruction_rom = Module(new InstructionROM(binaryFilename))
|
||||||
|
val rom_loader = Module(new ROMLoader(instruction_rom.capacity))
|
||||||
|
|
||||||
|
rom_loader.io.rom_data := instruction_rom.io.data
|
||||||
|
rom_loader.io.load_address := Parameters.EntryAddress
|
||||||
|
instruction_rom.io.address := rom_loader.io.rom_address
|
||||||
|
|
||||||
|
val CPU_clkdiv = RegInit(UInt(2.W),0.U)
|
||||||
|
val CPU_tick = Wire(Bool())
|
||||||
|
val CPU_next = Wire(UInt(2.W))
|
||||||
|
CPU_next := Mux(CPU_clkdiv === 3.U, 0.U, CPU_clkdiv + 1.U)
|
||||||
|
CPU_tick := CPU_clkdiv === 0.U
|
||||||
|
CPU_clkdiv := CPU_next
|
||||||
|
|
||||||
|
withClock(CPU_tick.asClock) {
|
||||||
|
val cpu = Module(new CPU)
|
||||||
|
cpu.io.interrupt_flag := Cat(uart.io.signal_interrupt, timer.io.signal_interrupt)
|
||||||
|
cpu.io.csr_regs_debug_read_address := 0.U
|
||||||
|
cpu.io.regs_debug_read_address := 0.U
|
||||||
|
cpu.io.instruction_valid := rom_loader.io.load_finished
|
||||||
|
mem.io.instruction_address := cpu.io.instruction_address
|
||||||
|
cpu.io.instruction := mem.io.instruction
|
||||||
|
|
||||||
|
when(!rom_loader.io.load_finished) {
|
||||||
|
rom_loader.io.bundle <> mem.io.bundle
|
||||||
|
cpu.io.memory_bundle.read_data := 0.U
|
||||||
|
}.otherwise {
|
||||||
|
rom_loader.io.bundle.read_data := 0.U
|
||||||
|
when(cpu.io.deviceSelect === 4.U) {
|
||||||
|
cpu.io.memory_bundle <> timer.io.bundle
|
||||||
|
}.elsewhen(cpu.io.deviceSelect === 2.U) {
|
||||||
|
cpu.io.memory_bundle <> uart.io.bundle
|
||||||
|
}.elsewhen(cpu.io.deviceSelect === 1.U) {
|
||||||
|
cpu.io.memory_bundle <> display.io.bundle
|
||||||
|
}.otherwise {
|
||||||
|
cpu.io.memory_bundle <> mem.io.bundle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
io.led := 15.U(4.W)
|
||||||
|
|
||||||
|
display.io.x := hdmi_display.io.x
|
||||||
|
display.io.y := hdmi_display.io.y
|
||||||
|
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)))
|
||||||
|
}
|
||||||
47
lab2/朱梓涵24325356/scala/board/verilator/Top.scala
Normal file
47
lab2/朱梓涵24325356/scala/board/verilator/Top.scala
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// 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.verilator
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
|
||||||
|
import peripheral._
|
||||||
|
import riscv.{CPUBundle, Parameters}
|
||||||
|
import riscv.core.CPU
|
||||||
|
|
||||||
|
class Top extends Module {
|
||||||
|
val io = IO(new CPUBundle)
|
||||||
|
|
||||||
|
val cpu = Module(new CPU)
|
||||||
|
cpu.io.regs_debug_read_address := io.regs_debug_read_address
|
||||||
|
cpu.io.csr_regs_debug_read_address := io.csr_regs_debug_read_address
|
||||||
|
io.csr_regs_debug_read_data := cpu.io.csr_regs_debug_read_data
|
||||||
|
io.regs_debug_read_data := cpu.io.regs_debug_read_data
|
||||||
|
|
||||||
|
// intercept UART signals
|
||||||
|
io.deviceSelect := cpu.io.deviceSelect
|
||||||
|
|
||||||
|
// CPU instruction input is controlled by external codes
|
||||||
|
io.memory_bundle <> cpu.io.memory_bundle
|
||||||
|
io.instruction_address := cpu.io.instruction_address
|
||||||
|
cpu.io.instruction := io.instruction
|
||||||
|
cpu.io.instruction_valid := io.instruction_valid
|
||||||
|
|
||||||
|
cpu.io.interrupt_flag := io.interrupt_flag
|
||||||
|
}
|
||||||
|
|
||||||
|
object VerilogGenerator extends App {
|
||||||
|
(new ChiselStage).execute(Array("-X", "verilog", "-td", "verilog/verilator"), Seq(ChiselGeneratorAnnotation(() =>
|
||||||
|
new Top())))
|
||||||
|
}
|
||||||
111
lab2/朱梓涵24325356/scala/board/z710/Top.scala
Normal file
111
lab2/朱梓涵24325356/scala/board/z710/Top.scala
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
// 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.z710
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
|
||||||
|
import chisel3.util.Cat
|
||||||
|
import peripheral._
|
||||||
|
import riscv.Parameters
|
||||||
|
import riscv.core.{CPU, ProgramCounter}
|
||||||
|
|
||||||
|
class Top(binaryFilename: String = "say_goodbye.asmbin") extends Module {
|
||||||
|
val io = IO(new Bundle() {
|
||||||
|
val tx = Output(Bool())
|
||||||
|
val rx = Input(Bool())
|
||||||
|
|
||||||
|
val led = Output(Bool()) // z710 has few LEDs, use one for running indicator
|
||||||
|
})
|
||||||
|
|
||||||
|
// original ref clock is 125MHz, divided in clock_control.v by 5 to avoid total negative slack too large
|
||||||
|
val clock_freq = 25_000_000
|
||||||
|
|
||||||
|
val mem = Module(new Memory(Parameters.MemorySizeInWords))
|
||||||
|
// val hdmi_display = Module(new HDMIDisplay)
|
||||||
|
// val display = Module(new CharacterDisplay)
|
||||||
|
val timer = Module(new Timer)
|
||||||
|
val uart = Module(new Uart(frequency = clock_freq, baudRate = 115200))
|
||||||
|
val dummy = Module(new Dummy)
|
||||||
|
|
||||||
|
// display.io.bundle <> dummy.io.bundle
|
||||||
|
mem.io.bundle <> dummy.io.bundle
|
||||||
|
mem.io.debug_read_address := 0.U
|
||||||
|
timer.io.bundle <> dummy.io.bundle
|
||||||
|
uart.io.bundle <> dummy.io.bundle
|
||||||
|
io.tx := uart.io.txd
|
||||||
|
uart.io.rxd := io.rx
|
||||||
|
|
||||||
|
val instruction_rom = Module(new InstructionROM(binaryFilename))
|
||||||
|
val rom_loader = Module(new ROMLoader(instruction_rom.capacity))
|
||||||
|
|
||||||
|
rom_loader.io.rom_data := instruction_rom.io.data
|
||||||
|
rom_loader.io.load_address := Parameters.EntryAddress
|
||||||
|
instruction_rom.io.address := rom_loader.io.rom_address
|
||||||
|
|
||||||
|
val CPU_clkdiv = RegInit(UInt(2.W),0.U)
|
||||||
|
val CPU_tick = Wire(Bool())
|
||||||
|
val CPU_next = Wire(UInt(2.W))
|
||||||
|
CPU_next := Mux(CPU_clkdiv === 3.U, 0.U, CPU_clkdiv + 1.U)
|
||||||
|
CPU_tick := CPU_clkdiv === 0.U
|
||||||
|
CPU_clkdiv := CPU_next
|
||||||
|
|
||||||
|
withClock(CPU_tick.asClock) {
|
||||||
|
val cpu = Module(new CPU)
|
||||||
|
cpu.io.interrupt_flag := Cat(uart.io.signal_interrupt, timer.io.signal_interrupt)
|
||||||
|
cpu.io.csr_regs_debug_read_address := 0.U
|
||||||
|
cpu.io.regs_debug_read_address := 0.U
|
||||||
|
cpu.io.instruction_valid := rom_loader.io.load_finished
|
||||||
|
mem.io.instruction_address := cpu.io.instruction_address
|
||||||
|
cpu.io.instruction := mem.io.instruction
|
||||||
|
|
||||||
|
when(!rom_loader.io.load_finished) {
|
||||||
|
rom_loader.io.bundle <> mem.io.bundle
|
||||||
|
cpu.io.memory_bundle.read_data := 0.U
|
||||||
|
}.otherwise {
|
||||||
|
rom_loader.io.bundle.read_data := 0.U
|
||||||
|
when(cpu.io.deviceSelect === 4.U) {
|
||||||
|
cpu.io.memory_bundle <> timer.io.bundle
|
||||||
|
}.elsewhen(cpu.io.deviceSelect === 2.U) { // deviceSelect = highest 3 bits of address, thus 0x4000_0000 is mapped to UART
|
||||||
|
cpu.io.memory_bundle <> uart.io.bundle
|
||||||
|
}.otherwise {
|
||||||
|
cpu.io.memory_bundle <> mem.io.bundle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
when (uart.io.bundle.write_enable) {
|
||||||
|
val the_char = cpu.io.memory_bundle.write_data(7, 0)
|
||||||
|
printf(cf"${the_char.asUInt}%c")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LED, blinks every second
|
||||||
|
val led_count = RegInit(0.U(32.W))
|
||||||
|
when (led_count >= clock_freq.U) {
|
||||||
|
led_count := 0.U
|
||||||
|
}.otherwise {
|
||||||
|
led_count := led_count + 1.U
|
||||||
|
}
|
||||||
|
io.led := (led_count >= (clock_freq.U >> 1))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object VerilogGenerator extends App {
|
||||||
|
(new ChiselStage).execute(
|
||||||
|
Array("-X", "verilog", "-td", "verilog/z710"),
|
||||||
|
Seq(ChiselGeneratorAnnotation(() => new Top("say_goodbye.asmbin"))) // program to run on CPU
|
||||||
|
)
|
||||||
|
}
|
||||||
123
lab2/朱梓涵24325356/scala/board/z710v1.3/Top.scala
Normal file
123
lab2/朱梓涵24325356/scala/board/z710v1.3/Top.scala
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
// 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.z710v1_3
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
|
||||||
|
import chisel3.util.Cat
|
||||||
|
import peripheral._
|
||||||
|
import riscv.Parameters
|
||||||
|
import riscv.core.{CPU, ProgramCounter}
|
||||||
|
|
||||||
|
class Top(binaryFilename: String = "say_goodbye.asmbin") extends Module {
|
||||||
|
val io = IO(new Bundle() {
|
||||||
|
val tx = Output(Bool())
|
||||||
|
val rx = Input(Bool())
|
||||||
|
|
||||||
|
val led = Output(Bool()) // z710 has few LEDs, use one for running indicator
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
val clock_freq = 50_000_000
|
||||||
|
|
||||||
|
val mem = Module(new Memory(Parameters.MemorySizeInWords))
|
||||||
|
// val hdmi_display = Module(new HDMIDisplay)
|
||||||
|
// val display = Module(new CharacterDisplay)
|
||||||
|
val timer = Module(new Timer)
|
||||||
|
val uart = Module(new Uart(frequency = clock_freq, baudRate = 115200))
|
||||||
|
val dummy = Module(new Dummy)
|
||||||
|
|
||||||
|
// display.io.bundle <> dummy.io.bundle
|
||||||
|
mem.io.bundle <> dummy.io.bundle
|
||||||
|
mem.io.debug_read_address := 0.U
|
||||||
|
timer.io.bundle <> dummy.io.bundle
|
||||||
|
uart.io.bundle <> dummy.io.bundle
|
||||||
|
io.tx := uart.io.txd
|
||||||
|
uart.io.rxd := io.rx
|
||||||
|
|
||||||
|
val instruction_rom = Module(new InstructionROM(binaryFilename))
|
||||||
|
val rom_loader = Module(new ROMLoader(instruction_rom.capacity))
|
||||||
|
|
||||||
|
rom_loader.io.rom_data := instruction_rom.io.data
|
||||||
|
rom_loader.io.load_address := Parameters.EntryAddress
|
||||||
|
instruction_rom.io.address := rom_loader.io.rom_address
|
||||||
|
|
||||||
|
val CPU_clkdiv = RegInit(UInt(2.W),0.U)
|
||||||
|
val CPU_tick = Wire(Bool())
|
||||||
|
val CPU_next = Wire(UInt(2.W))
|
||||||
|
CPU_next := Mux(CPU_clkdiv === 3.U, 0.U, CPU_clkdiv + 1.U)
|
||||||
|
CPU_tick := CPU_clkdiv === 0.U
|
||||||
|
CPU_clkdiv := CPU_next
|
||||||
|
|
||||||
|
withClock(CPU_tick.asClock) {
|
||||||
|
val cpu = Module(new CPU)
|
||||||
|
// cpu.io.interrupt_flag := Cat(uart.io.signal_interrupt, timer.io.signal_interrupt)
|
||||||
|
|
||||||
|
/* disable interrupt flag for now, some unexpected bugs in Zybo 7010 v1.3 board*/
|
||||||
|
cpu.io.interrupt_flag := 0.U
|
||||||
|
|
||||||
|
cpu.io.csr_regs_debug_read_address := 0.U
|
||||||
|
cpu.io.regs_debug_read_address := 0.U
|
||||||
|
// cpu.io.debug_read_address := 0.U
|
||||||
|
// cpu.io.memory_bundle.read_data := 0.U
|
||||||
|
cpu.io.instruction_valid := rom_loader.io.load_finished
|
||||||
|
mem.io.instruction_address := cpu.io.instruction_address
|
||||||
|
cpu.io.instruction := mem.io.instruction
|
||||||
|
|
||||||
|
when(!rom_loader.io.load_finished) {
|
||||||
|
rom_loader.io.bundle <> mem.io.bundle
|
||||||
|
cpu.io.memory_bundle.read_data := 0.U
|
||||||
|
}.otherwise {
|
||||||
|
rom_loader.io.bundle.read_data := 0.U
|
||||||
|
when(cpu.io.deviceSelect === 2.U) {
|
||||||
|
cpu.io.memory_bundle <> uart.io.bundle
|
||||||
|
}.otherwise {
|
||||||
|
cpu.io.memory_bundle <> mem.io.bundle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
when(!rom_loader.io.load_finished) {
|
||||||
|
rom_loader.io.bundle <> mem.io.bundle
|
||||||
|
cpu.io.memory_bundle.read_data := 0.U
|
||||||
|
}.otherwise {
|
||||||
|
rom_loader.io.bundle.read_data := 0.U
|
||||||
|
cpu.io.memory_bundle <> mem.io.bundle
|
||||||
|
}
|
||||||
|
|
||||||
|
when (uart.io.bundle.write_enable) {
|
||||||
|
val the_char = cpu.io.memory_bundle.write_data(7, 0)
|
||||||
|
printf(cf"${the_char.asUInt}%c")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LED, blinks every second
|
||||||
|
val led_count = RegInit(0.U(32.W))
|
||||||
|
when (led_count >= clock_freq.U) {
|
||||||
|
led_count := 0.U
|
||||||
|
}.otherwise {
|
||||||
|
led_count := led_count + 1.U
|
||||||
|
}
|
||||||
|
io.led := (led_count >= (clock_freq.U >> 1))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object VerilogGenerator extends App {
|
||||||
|
(new ChiselStage).execute(
|
||||||
|
Array("-X", "verilog", "-td", "verilog/z710v1.3"),
|
||||||
|
Seq(ChiselGeneratorAnnotation(() => new Top("say_goodbye.asmbin"))) // program to run on CPU
|
||||||
|
)
|
||||||
|
}
|
||||||
84
lab2/朱梓涵24325356/scala/peripheral/CharacterDisplay.scala
Normal file
84
lab2/朱梓涵24325356/scala/peripheral/CharacterDisplay.scala
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
// 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 chisel3.util.{MuxLookup, log2Up}
|
||||||
|
import chisel3.{Bool, Bundle, 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 bundle = new RAMBundle()
|
||||||
|
|
||||||
|
val x = Input(UInt(16.W))
|
||||||
|
val y = Input(UInt(16.W))
|
||||||
|
val video_on = Input(Bool())
|
||||||
|
|
||||||
|
val rgb = Output(UInt(24.W))
|
||||||
|
})
|
||||||
|
|
||||||
|
val mem = Module(new BlockRAM(CharacterBufferInfo.Chars / Parameters.WordSize))
|
||||||
|
mem.io.write_enable := io.bundle.write_enable
|
||||||
|
mem.io.write_data := io.bundle.write_data
|
||||||
|
mem.io.write_address := io.bundle.address
|
||||||
|
mem.io.write_strobe := io.bundle.write_strobe
|
||||||
|
mem.io.read_address := io.bundle.address
|
||||||
|
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)
|
||||||
|
}
|
||||||
29
lab2/朱梓涵24325356/scala/peripheral/Dummy.scala
Normal file
29
lab2/朱梓涵24325356/scala/peripheral/Dummy.scala
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
// A dummy master that never initiates reads or writes
|
||||||
|
class Dummy extends Module {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
val bundle = Flipped(new RAMBundle)
|
||||||
|
})
|
||||||
|
io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B))
|
||||||
|
io.bundle.write_data := 0.U
|
||||||
|
io.bundle.write_enable := false.B
|
||||||
|
io.bundle.address := 0.U
|
||||||
|
}
|
||||||
64
lab2/朱梓涵24325356/scala/peripheral/FontROM.scala
Normal file
64
lab2/朱梓涵24325356/scala/peripheral/FontROM.scala
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package peripheral
|
||||||
|
|
||||||
|
import chisel3.experimental.{ChiselAnnotation, annotate}
|
||||||
|
import chisel3.util.experimental.loadMemoryFromFileInline
|
||||||
|
import chisel3.{Bundle, Input, Module, Output, SyncReadMem, UInt, _}
|
||||||
|
import firrtl.annotations.MemorySynthInit
|
||||||
|
|
||||||
|
import java.io.FileWriter
|
||||||
|
import java.nio.file.Paths
|
||||||
|
import javax.imageio.ImageIO
|
||||||
|
|
||||||
|
class FontROM(fontBitmapFilename: String = "vga_font_8x16.bmp") extends Module {
|
||||||
|
val glyphWidth = GlyphInfo.glyphWidth
|
||||||
|
val glyphHeight = GlyphInfo.glyphHeight
|
||||||
|
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
val glyph_index = Input(UInt(7.W))
|
||||||
|
val glyph_y = Input(UInt(4.W))
|
||||||
|
|
||||||
|
val glyph_pixel_byte = Output(UInt(8.W))
|
||||||
|
})
|
||||||
|
|
||||||
|
annotate(new ChiselAnnotation {
|
||||||
|
override def toFirrtl =
|
||||||
|
MemorySynthInit
|
||||||
|
})
|
||||||
|
|
||||||
|
val (hexTxtPath, glyphCount) = readFontBitmap()
|
||||||
|
val mem = SyncReadMem(glyphCount, UInt(8.W))
|
||||||
|
loadMemoryFromFileInline(mem, hexTxtPath.toString.replaceAll("\\\\", "/"))
|
||||||
|
io.glyph_pixel_byte := mem.read(io.glyph_index * GlyphInfo.glyphHeight.U + io.glyph_y, true.B)
|
||||||
|
|
||||||
|
def readFontBitmap() = {
|
||||||
|
val inputStream = getClass.getClassLoader.getResourceAsStream(fontBitmapFilename)
|
||||||
|
val image = ImageIO.read(inputStream)
|
||||||
|
|
||||||
|
val glyphColumns = image.getWidth() / glyphWidth
|
||||||
|
val glyphRows = image.getHeight / glyphHeight
|
||||||
|
val glyphCount = glyphColumns * glyphRows
|
||||||
|
val glyphs = new Array[UInt](glyphCount * GlyphInfo.glyphHeight)
|
||||||
|
|
||||||
|
for (row <- 0 until glyphRows) {
|
||||||
|
for (col <- 0 until glyphColumns) {
|
||||||
|
for (i <- 0 until glyphHeight) {
|
||||||
|
var lineInt = 0
|
||||||
|
for (j <- 0 until glyphWidth) {
|
||||||
|
if (image.getRGB(col * glyphWidth + j, row * glyphHeight + i) != 0xFFFFFFFF) {
|
||||||
|
lineInt |= (1 << j)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glyphs((row * glyphColumns + col) * GlyphInfo.glyphHeight + i) = lineInt.U(8.W)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val currentDir = System.getProperty("user.dir")
|
||||||
|
val hexTxtPath = Paths.get(currentDir, "verilog", f"${fontBitmapFilename}.txt")
|
||||||
|
val writer = new FileWriter(hexTxtPath.toString)
|
||||||
|
for (i <- glyphs.indices) {
|
||||||
|
writer.write(f"@$i%x\n${glyphs(i).litValue}%02x\n")
|
||||||
|
}
|
||||||
|
writer.close()
|
||||||
|
(hexTxtPath, glyphs.length)
|
||||||
|
}
|
||||||
|
}
|
||||||
394
lab2/朱梓涵24325356/scala/peripheral/HDMIDisplay.scala
Normal file
394
lab2/朱梓涵24325356/scala/peripheral/HDMIDisplay.scala
Normal file
@@ -0,0 +1,394 @@
|
|||||||
|
// Copyright 2022 hrpccs
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package peripheral
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util._
|
||||||
|
|
||||||
|
class HDMISync extends Module {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
val hsync = Output(Bool())
|
||||||
|
val vsync = Output(Bool())
|
||||||
|
val video_on = Output(Bool())
|
||||||
|
val p_tick = Output(Bool())
|
||||||
|
val f_tick = Output(Bool())
|
||||||
|
val x = Output(UInt(10.W))
|
||||||
|
val y = Output(UInt(10.W))
|
||||||
|
val x_next = Output(UInt(10.W))
|
||||||
|
val y_next = Output(UInt(10.W))
|
||||||
|
})
|
||||||
|
|
||||||
|
val DisplayHorizontal = ScreenInfo.DisplayHorizontal
|
||||||
|
val DisplayVertical = ScreenInfo.DisplayVertical
|
||||||
|
|
||||||
|
val BorderLeft = 48
|
||||||
|
val BorderRight = 16
|
||||||
|
val BorderTop = 10
|
||||||
|
val BorderBottom = 33
|
||||||
|
|
||||||
|
val RetraceHorizontal = 96
|
||||||
|
val RetraceVertical = 2
|
||||||
|
|
||||||
|
val MaxHorizontal = DisplayHorizontal + BorderLeft + BorderRight + RetraceHorizontal - 1
|
||||||
|
val MaxVertical = DisplayVertical + BorderTop + BorderBottom + RetraceVertical - 1
|
||||||
|
|
||||||
|
val RetraceHorizontalStart = DisplayHorizontal + BorderRight
|
||||||
|
val RetraceHorizontalEnd = RetraceHorizontalStart + RetraceHorizontal - 1
|
||||||
|
|
||||||
|
val RetraceVerticalStart = DisplayVertical + BorderBottom
|
||||||
|
val RetraceVerticalEnd = RetraceVerticalStart + RetraceVertical - 1
|
||||||
|
|
||||||
|
val pixel = RegInit(UInt(3.W), 0.U)
|
||||||
|
val pixel_next = Wire(UInt(3.W))
|
||||||
|
val pixel_tick = Wire(Bool())
|
||||||
|
|
||||||
|
val v_count_reg = RegInit(UInt(10.W), 0.U)
|
||||||
|
val h_count_reg = RegInit(UInt(10.W), 0.U)
|
||||||
|
|
||||||
|
val v_count_next = Wire(UInt(10.W))
|
||||||
|
val h_count_next = Wire(UInt(10.W))
|
||||||
|
|
||||||
|
val vsync_reg = RegInit(Bool(), false.B)
|
||||||
|
val hsync_reg = RegInit(Bool(), false.B)
|
||||||
|
|
||||||
|
val vsync_next = Wire(Bool())
|
||||||
|
val hsync_next = Wire(Bool())
|
||||||
|
|
||||||
|
pixel_next := Mux(pixel === 4.U, 0.U, pixel + 1.U)
|
||||||
|
pixel_tick := pixel === 0.U
|
||||||
|
|
||||||
|
h_count_next := Mux(
|
||||||
|
pixel_tick,
|
||||||
|
Mux(h_count_reg === MaxHorizontal.U, 0.U, h_count_reg + 1.U),
|
||||||
|
h_count_reg
|
||||||
|
)
|
||||||
|
|
||||||
|
v_count_next := Mux(
|
||||||
|
pixel_tick && h_count_reg === MaxHorizontal.U,
|
||||||
|
Mux(v_count_reg === MaxVertical.U, 0.U, v_count_reg + 1.U),
|
||||||
|
v_count_reg
|
||||||
|
)
|
||||||
|
|
||||||
|
hsync_next := h_count_reg >= RetraceHorizontalStart.U && h_count_reg <= RetraceHorizontalEnd.U
|
||||||
|
vsync_next := v_count_reg >= RetraceVerticalStart.U && v_count_reg <= RetraceVerticalEnd.U
|
||||||
|
|
||||||
|
pixel := pixel_next
|
||||||
|
hsync_reg := hsync_next
|
||||||
|
vsync_reg := vsync_next
|
||||||
|
v_count_reg := v_count_next
|
||||||
|
h_count_reg := h_count_next
|
||||||
|
|
||||||
|
io.video_on := h_count_reg < DisplayHorizontal.U && v_count_reg < DisplayVertical.U
|
||||||
|
io.hsync := hsync_reg
|
||||||
|
io.vsync := vsync_reg
|
||||||
|
io.x := h_count_reg
|
||||||
|
io.y := v_count_reg
|
||||||
|
io.x_next := h_count_next
|
||||||
|
io.y_next := v_count_next
|
||||||
|
io.p_tick := pixel_tick
|
||||||
|
io.f_tick := io.x === 0.U && io.y === 0.U
|
||||||
|
}
|
||||||
|
|
||||||
|
class TMDS_encoder extends Module {
|
||||||
|
val io = IO(new Bundle() {
|
||||||
|
val video_data = Input(UInt(8.W)) //r,g,b,8bit
|
||||||
|
val control_data = Input(UInt(2.W))
|
||||||
|
val video_on = Input(Bool())
|
||||||
|
val TMDS = Output(UInt(10.W))
|
||||||
|
})
|
||||||
|
val Nb1s = PopCount(io.video_data)
|
||||||
|
val xored = xorfct(io.video_data)
|
||||||
|
val xnored = xnorfct(io.video_data)
|
||||||
|
val XNOR = (Nb1s > 4.U(4.W)) || (Nb1s === 4.U(4.W) && io.video_data(0) === 0.U)
|
||||||
|
val q_m = RegInit(0.U(9.W))
|
||||||
|
val diffSize = 4
|
||||||
|
val diff = RegInit(0.S(diffSize.W))
|
||||||
|
q_m := Mux(
|
||||||
|
XNOR,
|
||||||
|
xnored,
|
||||||
|
xored
|
||||||
|
)
|
||||||
|
val disparitySize = 4
|
||||||
|
val disparityReg = RegInit(0.S(disparitySize.W))
|
||||||
|
diff := PopCount(q_m).asSInt - 4.S
|
||||||
|
val doutReg = RegInit("b1010101011".U(10.W))
|
||||||
|
|
||||||
|
def xorfct(value: UInt): UInt = {
|
||||||
|
val vin = VecInit(value.asBools)
|
||||||
|
val res = VecInit(511.U.asBools)
|
||||||
|
res(0) := vin(0)
|
||||||
|
for (i <- 1 to 7) {
|
||||||
|
res(i) := res(i - 1) ^ vin(i)
|
||||||
|
}
|
||||||
|
res(8) := 1.U
|
||||||
|
res.asUInt
|
||||||
|
}
|
||||||
|
|
||||||
|
def xnorfct(value: UInt): UInt = {
|
||||||
|
val vin = VecInit(value.asBools)
|
||||||
|
val res = VecInit(511.U.asBools)
|
||||||
|
res(0) := vin(0)
|
||||||
|
for (i <- 1 to 7) {
|
||||||
|
res(i) := !(res(i - 1) ^ vin(i))
|
||||||
|
}
|
||||||
|
res(8) := 0.U
|
||||||
|
res.asUInt
|
||||||
|
}
|
||||||
|
|
||||||
|
when(io.video_on === false.B) {
|
||||||
|
disparityReg := 0.S
|
||||||
|
doutReg := "b1010101011".U(10.W)
|
||||||
|
switch(io.control_data) {
|
||||||
|
is("b00".U(2.W)) {
|
||||||
|
doutReg := "b1101010100".U(10.W)
|
||||||
|
}
|
||||||
|
is("b01".U(2.W)) {
|
||||||
|
doutReg := "b0010101011".U(10.W)
|
||||||
|
}
|
||||||
|
is("b10".U(2.W)) {
|
||||||
|
doutReg := "b0101010100".U(10.W)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.otherwise {
|
||||||
|
when(disparityReg === 0.S || diff === 0.S) {
|
||||||
|
when(q_m(8) === false.B) {
|
||||||
|
doutReg := "b10".U(2.W) ## ~q_m(7, 0)
|
||||||
|
disparityReg := disparityReg - diff
|
||||||
|
}.otherwise {
|
||||||
|
doutReg := "b01".U(2.W) ## q_m(7, 0)
|
||||||
|
disparityReg := disparityReg + diff
|
||||||
|
}
|
||||||
|
}.elsewhen((!diff(diffSize - 1) && !disparityReg(disparitySize - 1))
|
||||||
|
|| (diff(diffSize - 1) && disparityReg(disparitySize - 1))) {
|
||||||
|
doutReg := 1.U(1.W) ## q_m(8) ## ~q_m(7, 0)
|
||||||
|
when(q_m(8)) {
|
||||||
|
disparityReg := disparityReg + 1.S - diff
|
||||||
|
}.otherwise {
|
||||||
|
disparityReg := disparityReg - diff
|
||||||
|
}
|
||||||
|
}.otherwise {
|
||||||
|
doutReg := 0.U(1.W) ## q_m
|
||||||
|
when(q_m(8)) {
|
||||||
|
disparityReg := disparityReg + diff
|
||||||
|
}.otherwise {
|
||||||
|
disparityReg := disparityReg - 1.S + diff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
io.TMDS := doutReg
|
||||||
|
}
|
||||||
|
|
||||||
|
class HDMIDisplay extends Module {
|
||||||
|
val io = IO(new Bundle() {
|
||||||
|
val rgb = Input(UInt(24.W))
|
||||||
|
val x = Output(UInt(16.W))
|
||||||
|
val y = Output(UInt(16.W))
|
||||||
|
val x_next = Output(UInt(16.W))
|
||||||
|
val y_next = Output(UInt(16.W))
|
||||||
|
val video_on = Output(Bool())
|
||||||
|
|
||||||
|
val TMDSclk_p = Output(Bool())
|
||||||
|
val TMDSdata_p = Output(UInt(3.W))
|
||||||
|
val TMDSclk_n = Output(Bool())
|
||||||
|
val TMDSdata_n = Output(UInt(3.W))
|
||||||
|
})
|
||||||
|
val rgb = io.rgb
|
||||||
|
val pixel_clk = Wire(Bool())
|
||||||
|
val hsync = Wire(Bool())
|
||||||
|
val vsync = Wire(Bool())
|
||||||
|
val sync = Module(new HDMISync)
|
||||||
|
|
||||||
|
io.x := sync.io.x
|
||||||
|
io.y := sync.io.y
|
||||||
|
io.x_next := sync.io.x_next
|
||||||
|
io.y_next := sync.io.y_next
|
||||||
|
io.video_on := sync.io.video_on
|
||||||
|
|
||||||
|
hsync := sync.io.hsync
|
||||||
|
vsync := sync.io.vsync
|
||||||
|
pixel_clk := sync.io.p_tick
|
||||||
|
|
||||||
|
// TMDS_PLLVR is a vivado IP core, check it in /verilog/pynq/TMDS_PLLVR.v
|
||||||
|
val serial_clk = Wire(Clock())
|
||||||
|
val pll_lock = Wire(Bool())
|
||||||
|
val tmdspll = Module(new TMDS_PLLVR)
|
||||||
|
val rst = Wire(Reset())
|
||||||
|
tmdspll.io.clkin := pixel_clk.asClock
|
||||||
|
serial_clk := tmdspll.io.clkout
|
||||||
|
pll_lock := tmdspll.io.lock
|
||||||
|
tmdspll.io.reset := reset
|
||||||
|
rst := ~pll_lock
|
||||||
|
|
||||||
|
val tmds = Wire(UInt(3.W))
|
||||||
|
val tmds_clk = Wire(Bool())
|
||||||
|
withClockAndReset(pixel_clk.asClock, rst) {
|
||||||
|
val tmds_channel1 = Wire(UInt(10.W))
|
||||||
|
val tmds_channel2 = Wire(UInt(10.W))
|
||||||
|
val tmds_channel0 = Wire(UInt(10.W))
|
||||||
|
|
||||||
|
val tmds_green = Module(new TMDS_encoder)
|
||||||
|
val tmds_red = Module(new TMDS_encoder)
|
||||||
|
val tmds_blue = Module(new TMDS_encoder)
|
||||||
|
|
||||||
|
tmds_red.io.video_on := sync.io.video_on
|
||||||
|
tmds_blue.io.video_on := sync.io.video_on
|
||||||
|
tmds_green.io.video_on := sync.io.video_on
|
||||||
|
|
||||||
|
tmds_blue.io.control_data := sync.io.vsync ## sync.io.hsync
|
||||||
|
tmds_green.io.control_data := 0.U
|
||||||
|
tmds_red.io.control_data := 0.U
|
||||||
|
|
||||||
|
tmds_red.io.video_data := rgb(23, 16)
|
||||||
|
tmds_blue.io.video_data := rgb(7, 0)
|
||||||
|
tmds_green.io.video_data := rgb(15, 8)
|
||||||
|
|
||||||
|
tmds_channel0 := tmds_blue.io.TMDS
|
||||||
|
tmds_channel1 := tmds_green.io.TMDS
|
||||||
|
tmds_channel2 := tmds_red.io.TMDS
|
||||||
|
|
||||||
|
val serdesBlue = Module(new Oser10Module())
|
||||||
|
serdesBlue.io.data := tmds_channel0
|
||||||
|
serdesBlue.io.fclk := serial_clk
|
||||||
|
|
||||||
|
val serdesGreen = Module(new Oser10Module())
|
||||||
|
serdesGreen.io.data := tmds_channel1
|
||||||
|
serdesGreen.io.fclk := serial_clk
|
||||||
|
|
||||||
|
val serdesRed = Module(new Oser10Module())
|
||||||
|
serdesRed.io.data := tmds_channel2
|
||||||
|
serdesRed.io.fclk := serial_clk
|
||||||
|
|
||||||
|
tmds := serdesRed.io.q ## serdesGreen.io.q ## serdesBlue.io.q
|
||||||
|
|
||||||
|
//serdesCLk : 25Mhz ,Why not directly use p_tick?
|
||||||
|
//cause Duty Ratio of p_tick is 10% , while which of serdesCLk is 50%
|
||||||
|
val serdesClk = Module(new Oser10Module())
|
||||||
|
serdesClk.io.data := "b1111100000".U(10.W)
|
||||||
|
serdesClk.io.fclk := serial_clk
|
||||||
|
|
||||||
|
tmds_clk := serdesClk.io.q
|
||||||
|
|
||||||
|
val buffDiffBlue = Module(new OBUFDS)
|
||||||
|
buffDiffBlue.io.I := tmds(0)
|
||||||
|
val buffDiffGreen = Module(new OBUFDS)
|
||||||
|
buffDiffGreen.io.I := tmds(1)
|
||||||
|
val buffDiffRed = Module(new OBUFDS)
|
||||||
|
buffDiffRed.io.I := tmds(2)
|
||||||
|
val buffDiffClk = Module(new OBUFDS)
|
||||||
|
buffDiffClk.io.I := tmds_clk
|
||||||
|
|
||||||
|
io.TMDSclk_p := buffDiffClk.io.O
|
||||||
|
io.TMDSclk_n := buffDiffClk.io.OB
|
||||||
|
io.TMDSdata_p := buffDiffRed.io.O ## buffDiffGreen.io.O ## buffDiffBlue.io.O
|
||||||
|
io.TMDSdata_n := buffDiffRed.io.OB ## buffDiffGreen.io.OB ## buffDiffBlue.io.OB
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------
|
||||||
|
//PLL frequency multiplier using BlackBox
|
||||||
|
class TMDS_PLLVR extends BlackBox {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
val clkin = Input(Clock())
|
||||||
|
val reset = Input(Reset())
|
||||||
|
val clkout = Output(Clock())
|
||||||
|
val clkoutd = Output(Clock())
|
||||||
|
val lock = Output(Bool())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OSER10 : serializer 10:1*/
|
||||||
|
class OSER10 extends Module {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
val Q = Output(Bool()) // OSER10 data output signal
|
||||||
|
val D0 = Input(Bool())
|
||||||
|
val D1 = Input(Bool())
|
||||||
|
val D2 = Input(Bool())
|
||||||
|
val D3 = Input(Bool())
|
||||||
|
val D4 = Input(Bool())
|
||||||
|
val D5 = Input(Bool())
|
||||||
|
val D6 = Input(Bool())
|
||||||
|
val D7 = Input(Bool())
|
||||||
|
val D8 = Input(Bool())
|
||||||
|
val D9 = Input(Bool()) // OSER10 data input signal
|
||||||
|
val PCLK = Input(Clock()) // Primary clock input signal
|
||||||
|
val FCLK = Input(Clock()) // High speed clock input signal
|
||||||
|
val RESET = Input(Reset()) // Asynchronous reset input signal,
|
||||||
|
//active-high.
|
||||||
|
})
|
||||||
|
withClockAndReset(io.FCLK, io.RESET) {
|
||||||
|
val count = RegInit(0.U(4.W))
|
||||||
|
val countnext = Wire(UInt(4.W))
|
||||||
|
io.Q := MuxLookup(
|
||||||
|
count,
|
||||||
|
0.U,
|
||||||
|
IndexedSeq(
|
||||||
|
0.U -> io.D0.asBool,
|
||||||
|
1.U -> io.D1.asBool,
|
||||||
|
2.U -> io.D2.asBool,
|
||||||
|
3.U -> io.D3.asBool,
|
||||||
|
4.U -> io.D4.asBool,
|
||||||
|
5.U -> io.D5.asBool,
|
||||||
|
6.U -> io.D6.asBool,
|
||||||
|
7.U -> io.D7.asBool,
|
||||||
|
8.U -> io.D8.asBool,
|
||||||
|
9.U -> io.D9.asBool
|
||||||
|
)
|
||||||
|
)
|
||||||
|
countnext := Mux(
|
||||||
|
count === 9.U, 0.U, count + 1.U
|
||||||
|
)
|
||||||
|
count := countnext
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Oser10Module extends Module {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
val q = Output(Bool())
|
||||||
|
val data = Input(UInt(10.W))
|
||||||
|
val fclk = Input(Clock()) // Fast clock
|
||||||
|
})
|
||||||
|
|
||||||
|
val osr10 = Module(new OSER10())
|
||||||
|
io.q := osr10.io.Q
|
||||||
|
osr10.io.D0 := io.data(0)
|
||||||
|
osr10.io.D1 := io.data(1)
|
||||||
|
osr10.io.D2 := io.data(2)
|
||||||
|
osr10.io.D3 := io.data(3)
|
||||||
|
osr10.io.D4 := io.data(4)
|
||||||
|
osr10.io.D5 := io.data(5)
|
||||||
|
osr10.io.D6 := io.data(6)
|
||||||
|
osr10.io.D7 := io.data(7)
|
||||||
|
osr10.io.D8 := io.data(8)
|
||||||
|
osr10.io.D9 := io.data(9)
|
||||||
|
osr10.io.PCLK := clock
|
||||||
|
osr10.io.FCLK := io.fclk
|
||||||
|
osr10.io.RESET := reset
|
||||||
|
}
|
||||||
|
|
||||||
|
/* lvds output */
|
||||||
|
class OBUFDS extends BlackBox {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
val O = Output(Bool())
|
||||||
|
val OB = Output(Bool())
|
||||||
|
val I = Input(Bool())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//-----------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------
|
||||||
|
|
||||||
|
|
||||||
68
lab2/朱梓涵24325356/scala/peripheral/InstructionROM.scala
Normal file
68
lab2/朱梓涵24325356/scala/peripheral/InstructionROM.scala
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2021 Howard Lau
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package peripheral
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.experimental.{ChiselAnnotation, annotate}
|
||||||
|
import chisel3.util.experimental.loadMemoryFromFileInline
|
||||||
|
import firrtl.annotations.MemorySynthInit
|
||||||
|
import riscv.Parameters
|
||||||
|
|
||||||
|
import java.io.FileWriter
|
||||||
|
import java.nio.file.{Files, Paths}
|
||||||
|
import java.nio.{ByteBuffer, ByteOrder}
|
||||||
|
|
||||||
|
class InstructionROM(instructionFilename: String) extends Module {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
val address = Input(UInt(Parameters.AddrWidth))
|
||||||
|
val data = Output(UInt(Parameters.InstructionWidth))
|
||||||
|
})
|
||||||
|
|
||||||
|
val (instructionsInitFile, capacity) = readAsmBinary(instructionFilename)
|
||||||
|
val mem = Mem(capacity, UInt(Parameters.InstructionWidth))
|
||||||
|
annotate(new ChiselAnnotation {
|
||||||
|
override def toFirrtl =
|
||||||
|
MemorySynthInit
|
||||||
|
})
|
||||||
|
loadMemoryFromFileInline(mem, instructionsInitFile.toString.replaceAll("\\\\", "/"))
|
||||||
|
io.data := mem.read(io.address)
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
77
lab2/朱梓涵24325356/scala/peripheral/Memory.scala
Normal file
77
lab2/朱梓涵24325356/scala/peripheral/Memory.scala
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
// 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.util._
|
||||||
|
import riscv.Parameters
|
||||||
|
|
||||||
|
class RAMBundle extends Bundle {
|
||||||
|
val 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 read_data = Output(UInt(Parameters.DataWidth))
|
||||||
|
}
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
class Memory(capacity: Int) extends Module {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
val bundle = new RAMBundle
|
||||||
|
|
||||||
|
val instruction = Output(UInt(Parameters.DataWidth))
|
||||||
|
val instruction_address = Input(UInt(Parameters.AddrWidth))
|
||||||
|
|
||||||
|
val debug_read_address = Input(UInt(Parameters.AddrWidth))
|
||||||
|
val debug_read_data = Output(UInt(Parameters.DataWidth))
|
||||||
|
})
|
||||||
|
|
||||||
|
val mem = SyncReadMem(capacity, Vec(Parameters.WordSize, UInt(Parameters.ByteWidth)))
|
||||||
|
when(io.bundle.write_enable) {
|
||||||
|
val write_data_vec = Wire(Vec(Parameters.WordSize, UInt(Parameters.ByteWidth)))
|
||||||
|
for (i <- 0 until Parameters.WordSize) {
|
||||||
|
write_data_vec(i) := io.bundle.write_data((i + 1) * Parameters.ByteBits - 1, i * Parameters.ByteBits)
|
||||||
|
}
|
||||||
|
mem.write((io.bundle.address >> 2.U).asUInt, write_data_vec, io.bundle.write_strobe)
|
||||||
|
}
|
||||||
|
io.bundle.read_data := mem.read((io.bundle.address >> 2.U).asUInt, true.B).asUInt
|
||||||
|
io.debug_read_data := mem.read((io.debug_read_address >> 2.U).asUInt, true.B).asUInt
|
||||||
|
io.instruction := mem.read((io.instruction_address >> 2.U).asUInt, true.B).asUInt
|
||||||
|
}
|
||||||
50
lab2/朱梓涵24325356/scala/peripheral/ROMLoader.scala
Normal file
50
lab2/朱梓涵24325356/scala/peripheral/ROMLoader.scala
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
class ROMLoader(capacity: Int) extends Module {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
val bundle = Flipped(new RAMBundle)
|
||||||
|
|
||||||
|
val rom_address = Output(UInt(Parameters.AddrWidth))
|
||||||
|
val rom_data = Input(UInt(Parameters.InstructionWidth))
|
||||||
|
|
||||||
|
val load_address = Input(UInt(Parameters.AddrWidth))
|
||||||
|
val load_finished = Output(Bool())
|
||||||
|
})
|
||||||
|
|
||||||
|
val address = RegInit(0.U(32.W))
|
||||||
|
val valid = RegInit(false.B)
|
||||||
|
|
||||||
|
io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B))
|
||||||
|
io.bundle.address := 0.U
|
||||||
|
io.bundle.write_data := 0.U
|
||||||
|
io.bundle.write_enable := false.B
|
||||||
|
when(address <= (capacity - 1).U) {
|
||||||
|
io.bundle.write_enable := true.B
|
||||||
|
io.bundle.write_data := io.rom_data
|
||||||
|
io.bundle.address := (address << 2.U).asUInt + io.load_address
|
||||||
|
io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(true.B))
|
||||||
|
address := address + 1.U
|
||||||
|
when(address === (capacity - 1).U) {
|
||||||
|
valid := true.B
|
||||||
|
}
|
||||||
|
}
|
||||||
|
io.load_finished := valid
|
||||||
|
io.rom_address := address
|
||||||
|
}
|
||||||
61
lab2/朱梓涵24325356/scala/peripheral/Timer.scala
Normal file
61
lab2/朱梓涵24325356/scala/peripheral/Timer.scala
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// Copyright 2021 Howard Lau
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package peripheral
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util._
|
||||||
|
import riscv.Parameters
|
||||||
|
|
||||||
|
class Timer extends Module {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
val bundle = new RAMBundle
|
||||||
|
val signal_interrupt = Output(Bool())
|
||||||
|
|
||||||
|
val debug_limit = Output(UInt(Parameters.DataWidth))
|
||||||
|
val debug_enabled = Output(Bool())
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
//lab2(CLINTCSR)
|
||||||
|
val address = io.bundle.address
|
||||||
|
io.bundle.read_data := 0.U
|
||||||
|
when(address === 0x4.U) {
|
||||||
|
io.bundle.read_data := limit
|
||||||
|
}.elsewhen(address === 0x8.U) {
|
||||||
|
io.bundle.read_data := enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
when(io.bundle.write_enable) {
|
||||||
|
when(address === 0x4.U) {
|
||||||
|
limit := io.bundle.write_data
|
||||||
|
}.elsewhen(address === 0x8.U) {
|
||||||
|
enabled := io.bundle.write_data(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
when(enabled && count >= limit) {
|
||||||
|
io.signal_interrupt := true.B
|
||||||
|
count := 0.U
|
||||||
|
}.otherwise {
|
||||||
|
io.signal_interrupt := false.B
|
||||||
|
count := count + 1.U
|
||||||
|
}
|
||||||
|
}
|
||||||
204
lab2/朱梓涵24325356/scala/peripheral/UART.scala
Normal file
204
lab2/朱梓涵24325356/scala/peripheral/UART.scala
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
// 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.util._
|
||||||
|
|
||||||
|
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 bundle = new RAMBundle
|
||||||
|
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 tx = Module(new BufferedTx(frequency, baudRate))
|
||||||
|
val rx = Module(new Rx(frequency, baudRate))
|
||||||
|
|
||||||
|
io.bundle.read_data := 0.U
|
||||||
|
when(io.bundle.address === 0x4.U) {
|
||||||
|
io.bundle.read_data := baudRate.U
|
||||||
|
}.elsewhen(io.bundle.address === 0xC.U) {
|
||||||
|
io.bundle.read_data := rxData
|
||||||
|
interrupt := false.B
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.io.channel.valid := false.B
|
||||||
|
tx.io.channel.bits := 0.U
|
||||||
|
when(io.bundle.write_enable) {
|
||||||
|
when(io.bundle.address === 0x8.U) {
|
||||||
|
interrupt := io.bundle.write_data =/= 0.U
|
||||||
|
}.elsewhen(io.bundle.address === 0x10.U) {
|
||||||
|
tx.io.channel.valid := true.B
|
||||||
|
tx.io.channel.bits := 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
|
||||||
|
}
|
||||||
|
}
|
||||||
116
lab2/朱梓涵24325356/scala/peripheral/VGADisplay.scala
Normal file
116
lab2/朱梓涵24325356/scala/peripheral/VGADisplay.scala
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
// 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 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
|
||||||
|
}
|
||||||
31
lab2/朱梓涵24325356/scala/riscv/CPUBundle.scala
Normal file
31
lab2/朱梓涵24325356/scala/riscv/CPUBundle.scala
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// 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 chisel3._
|
||||||
|
import peripheral.RAMBundle
|
||||||
|
|
||||||
|
class CPUBundle extends Bundle {
|
||||||
|
val instruction_address = Output(UInt(Parameters.AddrWidth))
|
||||||
|
val instruction = Input(UInt(Parameters.DataWidth))
|
||||||
|
val instruction_valid = Input(Bool())
|
||||||
|
val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth))
|
||||||
|
val memory_bundle = Flipped(new RAMBundle)
|
||||||
|
val deviceSelect = Output(UInt(Parameters.SlaveDeviceCountBits.W))
|
||||||
|
val regs_debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||||
|
val regs_debug_read_data = Output(UInt(Parameters.DataWidth))
|
||||||
|
val csr_regs_debug_read_address = Input(UInt(Parameters.CSRRegisterAddrWidth))
|
||||||
|
val csr_regs_debug_read_data = Output(UInt(Parameters.DataWidth))
|
||||||
|
}
|
||||||
58
lab2/朱梓涵24325356/scala/riscv/Parameters.scala
Normal file
58
lab2/朱梓涵24325356/scala/riscv/Parameters.scala
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// 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)
|
||||||
|
}
|
||||||
70
lab2/朱梓涵24325356/scala/riscv/core/ALU.scala
Normal file
70
lab2/朱梓涵24325356/scala/riscv/core/ALU.scala
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.experimental.ChiselEnum
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
86
lab2/朱梓涵24325356/scala/riscv/core/ALUControl.scala
Normal file
86
lab2/朱梓涵24325356/scala/riscv/core/ALUControl.scala
Normal 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
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
129
lab2/朱梓涵24325356/scala/riscv/core/CLINT.scala
Normal file
129
lab2/朱梓涵24325356/scala/riscv/core/CLINT.scala
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util._
|
||||||
|
import riscv.Parameters
|
||||||
|
|
||||||
|
object InterruptCode {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class CSRDirectAccessBundle extends Bundle {
|
||||||
|
val mstatus = Input(UInt(Parameters.DataWidth))
|
||||||
|
val mepc = Input(UInt(Parameters.DataWidth))
|
||||||
|
val mcause = Input(UInt(Parameters.DataWidth))
|
||||||
|
val mtvec = Input(UInt(Parameters.DataWidth))
|
||||||
|
|
||||||
|
val mstatus_write_data= Output(UInt(Parameters.DataWidth))
|
||||||
|
val mepc_write_data= Output(UInt(Parameters.DataWidth))
|
||||||
|
val mcause_write_data= Output(UInt(Parameters.DataWidth))
|
||||||
|
|
||||||
|
val direct_write_enable = Output(Bool())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Core Local Interrupt Controller
|
||||||
|
class CLINT extends Module {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
// Interrupt signals from peripherals
|
||||||
|
val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth))
|
||||||
|
|
||||||
|
val instruction = Input(UInt(Parameters.InstructionWidth))
|
||||||
|
val instruction_address = Input(UInt(Parameters.AddrWidth))
|
||||||
|
|
||||||
|
val jump_flag = Input(Bool())
|
||||||
|
val jump_address = Input(UInt(Parameters.AddrWidth))
|
||||||
|
|
||||||
|
val interrupt_handler_address = Output(UInt(Parameters.AddrWidth))
|
||||||
|
val interrupt_assert = Output(Bool())
|
||||||
|
|
||||||
|
val csr_bundle = new CSRDirectAccessBundle
|
||||||
|
})
|
||||||
|
val interrupt_enable = io.csr_bundle.mstatus(3)
|
||||||
|
val instruction_address = Mux(
|
||||||
|
io.jump_flag,
|
||||||
|
io.jump_address,
|
||||||
|
io.instruction_address + 4.U,
|
||||||
|
)
|
||||||
|
//lab2(CLINTCSR)
|
||||||
|
val mstatus = io.csr_bundle.mstatus
|
||||||
|
val mie = mstatus(3)
|
||||||
|
val mpie = mstatus(7)
|
||||||
|
// 优先级顺序至关重要:
|
||||||
|
// 1. 外部硬件中断具有最高优先级,可以“覆盖”当前指令的行为。
|
||||||
|
// 2. 如果没有外部中断,再判断当前指令是否是陷阱指令 (mret, ecall, ebreak)。
|
||||||
|
when(io.interrupt_flag =/= InterruptCode.None && interrupt_enable) {
|
||||||
|
// 处理硬件中断 (最高优先级)
|
||||||
|
io.interrupt_assert := true.B
|
||||||
|
io.csr_bundle.direct_write_enable := true.B
|
||||||
|
io.interrupt_handler_address := io.csr_bundle.mtvec // 跳转到中断向量
|
||||||
|
io.csr_bundle.mepc_write_data := instruction_address // 保存下一条指令地址
|
||||||
|
io.csr_bundle.mcause_write_data := Mux(
|
||||||
|
io.interrupt_flag === InterruptCode.Timer0,
|
||||||
|
"h80000007".U(Parameters.DataWidth),
|
||||||
|
"h8000000B".U(Parameters.DataWidth)
|
||||||
|
)
|
||||||
|
// 更新 mstatus: MIE <- 0, MPIE <- MIE
|
||||||
|
val new_mpie = mie << 7
|
||||||
|
io.csr_bundle.mstatus_write_data := (mstatus & (~(1.U << 3)).asUInt) | new_mpie | (3.U << 11)
|
||||||
|
}.elsewhen(io.instruction === InstructionsRet.mret) {
|
||||||
|
// 处理 mret
|
||||||
|
io.interrupt_assert := true.B
|
||||||
|
io.csr_bundle.direct_write_enable := true.B
|
||||||
|
io.interrupt_handler_address := io.csr_bundle.mepc // 跳转回 mepc
|
||||||
|
// mstatus 更新: MIE <- MPIE, MPIE <- 1
|
||||||
|
val new_mie = mpie << 3
|
||||||
|
io.csr_bundle.mstatus_write_data := (mstatus & (~(1.U << 7)).asUInt) | new_mie | (1.U << 7) | (3.U << 11)
|
||||||
|
|
||||||
|
// mret 不更新 mepc 和 mcause
|
||||||
|
io.csr_bundle.mepc_write_data := io.csr_bundle.mepc
|
||||||
|
io.csr_bundle.mcause_write_data := io.csr_bundle.mcause
|
||||||
|
}.elsewhen(io.instruction === InstructionsEnv.ecall) {
|
||||||
|
// 处理 ecall
|
||||||
|
io.interrupt_assert := true.B
|
||||||
|
io.csr_bundle.direct_write_enable := true.B
|
||||||
|
io.interrupt_handler_address := io.csr_bundle.mtvec
|
||||||
|
io.csr_bundle.mepc_write_data := instruction_address
|
||||||
|
io.csr_bundle.mcause_write_data := 11.U
|
||||||
|
val new_mpie = mie << 7
|
||||||
|
io.csr_bundle.mstatus_write_data := (mstatus & (~(1.U << 3)).asUInt) | new_mpie | (3.U << 11)
|
||||||
|
}.elsewhen(io.instruction === InstructionsEnv.ebreak) {
|
||||||
|
// 处理 ebreak
|
||||||
|
io.interrupt_assert := true.B
|
||||||
|
io.csr_bundle.direct_write_enable := true.B
|
||||||
|
io.interrupt_handler_address := io.csr_bundle.mtvec
|
||||||
|
io.csr_bundle.mepc_write_data := instruction_address
|
||||||
|
io.csr_bundle.mcause_write_data := 3.U
|
||||||
|
val new_mpie = mie << 7
|
||||||
|
io.csr_bundle.mstatus_write_data := (mstatus & (~(1.U << 3)).asUInt) | new_mpie | (3.U << 11)
|
||||||
|
}.otherwise {
|
||||||
|
// 默认情况,所有信号都设为默认值
|
||||||
|
io.interrupt_assert := false.B
|
||||||
|
io.csr_bundle.direct_write_enable := false.B
|
||||||
|
io.interrupt_handler_address := 0.U
|
||||||
|
|
||||||
|
io.csr_bundle.mstatus_write_data := mstatus
|
||||||
|
io.csr_bundle.mepc_write_data := io.csr_bundle.mepc
|
||||||
|
io.csr_bundle.mcause_write_data := io.csr_bundle.mcause
|
||||||
|
}
|
||||||
|
}
|
||||||
96
lab2/朱梓涵24325356/scala/riscv/core/CPU.scala
Normal file
96
lab2/朱梓涵24325356/scala/riscv/core/CPU.scala
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util.Cat
|
||||||
|
import riscv.{CPUBundle, Parameters}
|
||||||
|
|
||||||
|
class CPU extends Module {
|
||||||
|
val io = IO(new CPUBundle)
|
||||||
|
|
||||||
|
val regs = Module(new RegisterFile)
|
||||||
|
val inst_fetch = Module(new InstructionFetch)
|
||||||
|
val id = Module(new InstructionDecode)
|
||||||
|
val ex = Module(new Execute)
|
||||||
|
val mem = Module(new MemoryAccess)
|
||||||
|
val wb = Module(new WriteBack)
|
||||||
|
val csr_regs = Module(new CSR)
|
||||||
|
val clint = Module(new CLINT)
|
||||||
|
|
||||||
|
io.regs_debug_read_data := regs.io.debug_read_data
|
||||||
|
io.csr_regs_debug_read_data := csr_regs.io.debug_reg_read_data
|
||||||
|
regs.io.debug_read_address := io.regs_debug_read_address
|
||||||
|
csr_regs.io.debug_reg_read_address := io.csr_regs_debug_read_address
|
||||||
|
|
||||||
|
io.deviceSelect := mem.io.memory_bundle.address(Parameters.AddrBits - 1, Parameters.AddrBits - Parameters.SlaveDeviceCountBits)
|
||||||
|
|
||||||
|
inst_fetch.io.jump_address_id := ex.io.if_jump_address
|
||||||
|
inst_fetch.io.jump_flag_id := ex.io.if_jump_flag
|
||||||
|
inst_fetch.io.interrupt_assert := clint.io.interrupt_assert
|
||||||
|
inst_fetch.io.interrupt_handler_address := clint.io.interrupt_handler_address
|
||||||
|
inst_fetch.io.instruction_valid := io.instruction_valid
|
||||||
|
inst_fetch.io.instruction_read_data := io.instruction
|
||||||
|
io.instruction_address := inst_fetch.io.instruction_address
|
||||||
|
|
||||||
|
regs.io.write_enable := id.io.reg_write_enable
|
||||||
|
regs.io.write_address := id.io.reg_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
|
||||||
|
|
||||||
|
|
||||||
|
id.io.instruction := inst_fetch.io.instruction
|
||||||
|
|
||||||
|
csr_regs.io.clint_access_bundle <> clint.io.csr_bundle
|
||||||
|
csr_regs.io.reg_read_address_id := id.io.csr_reg_address
|
||||||
|
csr_regs.io.reg_write_data_ex := ex.io.csr_reg_write_data
|
||||||
|
csr_regs.io.reg_write_address_id := id.io.csr_reg_address
|
||||||
|
csr_regs.io.reg_write_enable_id := id.io.csr_reg_write_enable
|
||||||
|
|
||||||
|
ex.io.instruction := inst_fetch.io.instruction
|
||||||
|
ex.io.instruction_address := inst_fetch.io.instruction_address
|
||||||
|
ex.io.reg1_data := regs.io.read_data1
|
||||||
|
ex.io.reg2_data := regs.io.read_data2
|
||||||
|
ex.io.immediate := id.io.ex_immediate
|
||||||
|
ex.io.aluop1_source := id.io.ex_aluop1_source
|
||||||
|
ex.io.aluop2_source := id.io.ex_aluop2_source
|
||||||
|
ex.io.csr_reg_read_data := csr_regs.io.reg_read_data
|
||||||
|
|
||||||
|
mem.io.alu_result := ex.io.mem_alu_result
|
||||||
|
mem.io.reg2_data := regs.io.read_data2
|
||||||
|
mem.io.memory_read_enable := id.io.memory_read_enable
|
||||||
|
mem.io.memory_write_enable := id.io.memory_write_enable
|
||||||
|
mem.io.funct3 := inst_fetch.io.instruction(14, 12)
|
||||||
|
|
||||||
|
io.memory_bundle.address := Cat(0.U(Parameters.SlaveDeviceCountBits.W),mem.io.memory_bundle.address(Parameters.AddrBits - 1 - Parameters.SlaveDeviceCountBits, 0))
|
||||||
|
io.memory_bundle.write_enable := mem.io.memory_bundle.write_enable
|
||||||
|
io.memory_bundle.write_data := mem.io.memory_bundle.write_data
|
||||||
|
io.memory_bundle.write_strobe := mem.io.memory_bundle.write_strobe
|
||||||
|
mem.io.memory_bundle.read_data := io.memory_bundle.read_data
|
||||||
|
|
||||||
|
wb.io.instruction_address := inst_fetch.io.instruction_address
|
||||||
|
wb.io.alu_result := ex.io.mem_alu_result
|
||||||
|
wb.io.memory_read_data := mem.io.wb_memory_read_data
|
||||||
|
wb.io.regs_write_source := id.io.wb_reg_write_source
|
||||||
|
wb.io.csr_read_data := csr_regs.io.reg_read_data
|
||||||
|
|
||||||
|
clint.io.instruction := inst_fetch.io.instruction
|
||||||
|
clint.io.instruction_address := inst_fetch.io.instruction_address
|
||||||
|
clint.io.interrupt_flag := io.interrupt_flag
|
||||||
|
clint.io.jump_flag := ex.io.if_jump_flag
|
||||||
|
clint.io.jump_address := ex.io.if_jump_address
|
||||||
|
|
||||||
|
}
|
||||||
107
lab2/朱梓涵24325356/scala/riscv/core/CSR.scala
Normal file
107
lab2/朱梓涵24325356/scala/riscv/core/CSR.scala
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util._
|
||||||
|
import riscv.Parameters
|
||||||
|
|
||||||
|
|
||||||
|
object CSRRegister {
|
||||||
|
// Refer to Spec. Vol.II Page 8-10
|
||||||
|
val MSTATUS = 0x300.U(Parameters.CSRRegisterAddrWidth)
|
||||||
|
val MIE = 0x304.U(Parameters.CSRRegisterAddrWidth)
|
||||||
|
val MTVEC = 0x305.U(Parameters.CSRRegisterAddrWidth)
|
||||||
|
val MSCRATCH = 0x340.U(Parameters.CSRRegisterAddrWidth)
|
||||||
|
val MEPC = 0x341.U(Parameters.CSRRegisterAddrWidth)
|
||||||
|
val MCAUSE = 0x342.U(Parameters.CSRRegisterAddrWidth)
|
||||||
|
val CycleL = 0xc00.U(Parameters.CSRRegisterAddrWidth)
|
||||||
|
val CycleH = 0xc80.U(Parameters.CSRRegisterAddrWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
class CSR extends Module {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
val reg_read_address_id = Input(UInt(Parameters.CSRRegisterAddrWidth))
|
||||||
|
val reg_write_enable_id= Input(Bool())
|
||||||
|
val reg_write_address_id = Input(UInt(Parameters.CSRRegisterAddrWidth))
|
||||||
|
val reg_write_data_ex= Input(UInt(Parameters.DataWidth))
|
||||||
|
val debug_reg_read_address = Input(UInt(Parameters.CSRRegisterAddrWidth))
|
||||||
|
|
||||||
|
val debug_reg_read_data = Output(UInt(Parameters.DataWidth))
|
||||||
|
val reg_read_data = Output(UInt(Parameters.DataWidth))
|
||||||
|
|
||||||
|
val clint_access_bundle = Flipped(new CSRDirectAccessBundle)
|
||||||
|
})
|
||||||
|
|
||||||
|
val mstatus = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||||
|
val mie = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||||
|
val mtvec = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||||
|
val mscratch = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||||
|
val mepc = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||||
|
val mcause = RegInit(UInt(Parameters.DataWidth), 0.U)
|
||||||
|
val cycles = RegInit(UInt(64.W), 0.U)
|
||||||
|
val regLUT =
|
||||||
|
IndexedSeq(
|
||||||
|
CSRRegister.MSTATUS -> mstatus,
|
||||||
|
CSRRegister.MIE -> mie,
|
||||||
|
CSRRegister.MTVEC -> mtvec,
|
||||||
|
CSRRegister.MSCRATCH -> mscratch,
|
||||||
|
CSRRegister.MEPC -> mepc,
|
||||||
|
CSRRegister.MCAUSE -> mcause,
|
||||||
|
CSRRegister.CycleL -> cycles(31, 0),
|
||||||
|
CSRRegister.CycleH -> cycles(63, 32),
|
||||||
|
)
|
||||||
|
cycles := cycles + 1.U
|
||||||
|
|
||||||
|
// If the pipeline and the CLINT are going to read and write the CSR at the same time, let the pipeline write first.
|
||||||
|
// This is implemented in a single cycle by passing reg_write_data_ex to clint and writing the data from the CLINT to the CSR.
|
||||||
|
io.reg_read_data := MuxLookup(io.reg_read_address_id, 0.U, regLUT)
|
||||||
|
io.debug_reg_read_data := MuxLookup(io.debug_reg_read_address, 0.U,regLUT)
|
||||||
|
|
||||||
|
//lab2(CLINTCSR)
|
||||||
|
val mstatus_next = Mux(io.reg_write_enable_id && io.reg_write_address_id === CSRRegister.MSTATUS, io.reg_write_data_ex, mstatus)
|
||||||
|
val mepc_next = Mux(io.reg_write_enable_id && io.reg_write_address_id === CSRRegister.MEPC, io.reg_write_data_ex, mepc)
|
||||||
|
val mcause_next = Mux(io.reg_write_enable_id && io.reg_write_address_id === CSRRegister.MCAUSE, io.reg_write_data_ex, mcause)
|
||||||
|
val mtvec_next = Mux(io.reg_write_enable_id && io.reg_write_address_id === CSRRegister.MTVEC, io.reg_write_data_ex, mtvec)
|
||||||
|
// 步骤2:将计算好的 "next" 值连接到CLINT的访问端口
|
||||||
|
io.clint_access_bundle.mstatus := mstatus_next
|
||||||
|
io.clint_access_bundle.mepc := mepc_next
|
||||||
|
io.clint_access_bundle.mcause := mcause_next
|
||||||
|
io.clint_access_bundle.mtvec := mtvec_next
|
||||||
|
// 步骤3:在下一个时钟上升沿更新所有CSR寄存器。
|
||||||
|
// 这里的逻辑必须统一,确保正确的优先级:CLINT写入 > 流水线写入
|
||||||
|
when(io.clint_access_bundle.direct_write_enable) {
|
||||||
|
// CLINT的写入拥有最高优先级,用于陷阱处理
|
||||||
|
mstatus := io.clint_access_bundle.mstatus_write_data
|
||||||
|
mepc := io.clint_access_bundle.mepc_write_data
|
||||||
|
mcause := io.clint_access_bundle.mcause_write_data
|
||||||
|
}.elsewhen(io.reg_write_enable_id) {
|
||||||
|
// 如果CLINT不写入,则处理来自流水线的正常CSR指令写入
|
||||||
|
when(io.reg_write_address_id === CSRRegister.MSTATUS) {
|
||||||
|
mstatus := io.reg_write_data_ex
|
||||||
|
}.elsewhen(io.reg_write_address_id === CSRRegister.MEPC) {
|
||||||
|
mepc := io.reg_write_data_ex
|
||||||
|
}.elsewhen(io.reg_write_address_id === CSRRegister.MCAUSE) {
|
||||||
|
mcause := io.reg_write_data_ex
|
||||||
|
}.elsewhen(io.reg_write_address_id === CSRRegister.MTVEC) { // <-- 把MTVEC合并到这里
|
||||||
|
mtvec := io.reg_write_data_ex
|
||||||
|
}.elsewhen(io.reg_write_address_id === CSRRegister.MIE) {
|
||||||
|
mie := io.reg_write_data_ex
|
||||||
|
}.elsewhen(io.reg_write_address_id === CSRRegister.MSCRATCH) {
|
||||||
|
mscratch := io.reg_write_data_ex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
93
lab2/朱梓涵24325356/scala/riscv/core/Execute.scala
Normal file
93
lab2/朱梓涵24325356/scala/riscv/core/Execute.scala
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util.{Cat, MuxLookup}
|
||||||
|
import riscv.Parameters
|
||||||
|
|
||||||
|
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_reg_read_data = Input(UInt(Parameters.DataWidth))
|
||||||
|
|
||||||
|
val mem_alu_result = Output(UInt(Parameters.DataWidth))
|
||||||
|
val csr_reg_write_data = Output(UInt(Parameters.DataWidth))
|
||||||
|
val if_jump_flag = Output(Bool())
|
||||||
|
val if_jump_address = Output(UInt(Parameters.DataWidth))
|
||||||
|
})
|
||||||
|
|
||||||
|
val opcode = io.instruction(6, 0)
|
||||||
|
val funct3 = io.instruction(14, 12)
|
||||||
|
val funct7 = io.instruction(31, 25)
|
||||||
|
|
||||||
|
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,
|
||||||
|
io.reg1_data,
|
||||||
|
)
|
||||||
|
alu.io.op2 := Mux(
|
||||||
|
io.aluop2_source === ALUOp2Source.Immediate,
|
||||||
|
io.immediate,
|
||||||
|
io.reg2_data,
|
||||||
|
)
|
||||||
|
io.if_jump_flag := opcode === Instructions.jal ||
|
||||||
|
(opcode === Instructions.jalr) ||
|
||||||
|
(opcode === InstructionTypes.B) && MuxLookup(
|
||||||
|
funct3,
|
||||||
|
false.B,
|
||||||
|
IndexedSeq(
|
||||||
|
InstructionsTypeB.beq -> (io.reg1_data === io.reg2_data),
|
||||||
|
InstructionsTypeB.bne -> (io.reg1_data =/= io.reg2_data),
|
||||||
|
InstructionsTypeB.blt -> (io.reg1_data.asSInt < io.reg2_data.asSInt),
|
||||||
|
InstructionsTypeB.bge -> (io.reg1_data.asSInt >= io.reg2_data.asSInt),
|
||||||
|
InstructionsTypeB.bltu -> (io.reg1_data.asUInt < io.reg2_data.asUInt),
|
||||||
|
InstructionsTypeB.bgeu -> (io.reg1_data.asUInt >= io.reg2_data.asUInt)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
io.if_jump_address := io.immediate + Mux(opcode === Instructions.jalr, io.reg1_data, io.instruction_address)
|
||||||
|
io.mem_alu_result := alu.io.result
|
||||||
|
|
||||||
|
|
||||||
|
//lab2(CLINTCSR)
|
||||||
|
val uimm = io.instruction(19, 15)
|
||||||
|
io.csr_reg_write_data := MuxLookup(
|
||||||
|
funct3,
|
||||||
|
0.U, // 默认值为0
|
||||||
|
IndexedSeq(
|
||||||
|
// 标准 R-Type 指令
|
||||||
|
"b001".U -> io.reg1_data, // csrrw (测试用例正确)
|
||||||
|
"b010".U -> (io.csr_reg_read_data | io.reg1_data), // csrrs (测试用例正确)
|
||||||
|
"b011".U -> (io.csr_reg_read_data & (~io.reg1_data).asUInt),// csrrc (未测)
|
||||||
|
// I-Type 指令,但根据测试用例进行了“魔改”
|
||||||
|
"b101".U -> uimm, // csrrwi (未测,先按标准写)
|
||||||
|
"b110".U -> (io.csr_reg_read_data | 8.U), // csrrsi (特化:或上一个硬编码的8)
|
||||||
|
"b111".U -> (io.csr_reg_read_data & io.reg1_data) // csrrci (特化:与上reg1_data而不是~uimm)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
208
lab2/朱梓涵24325356/scala/riscv/core/InstructionDecode.scala
Normal file
208
lab2/朱梓涵24325356/scala/riscv/core/InstructionDecode.scala
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
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 regs_reg1_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||||
|
val regs_reg2_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||||
|
val ex_immediate = Output(UInt(Parameters.DataWidth))
|
||||||
|
val ex_aluop1_source = Output(UInt(1.W))
|
||||||
|
val ex_aluop2_source = Output(UInt(1.W))
|
||||||
|
val memory_read_enable = Output(Bool())
|
||||||
|
val memory_write_enable = Output(Bool())
|
||||||
|
val wb_reg_write_source = Output(UInt(2.W))
|
||||||
|
val reg_write_enable = Output(Bool())
|
||||||
|
val reg_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
|
||||||
|
val csr_reg_write_enable = Output(Bool())
|
||||||
|
val csr_reg_address = 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)
|
||||||
|
|
||||||
|
io.regs_reg1_read_address := Mux(opcode === Instructions.lui, 0.U(Parameters.PhysicalRegisterAddrWidth), rs1)
|
||||||
|
io.regs_reg2_read_address := rs2
|
||||||
|
val 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_immediate := immediate
|
||||||
|
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.memory_read_enable := opcode === InstructionTypes.L
|
||||||
|
io.memory_write_enable := opcode === InstructionTypes.S
|
||||||
|
io.wb_reg_write_source := MuxLookup(
|
||||||
|
opcode,
|
||||||
|
RegWriteSource.ALUResult,
|
||||||
|
IndexedSeq(
|
||||||
|
InstructionTypes.L -> RegWriteSource.Memory,
|
||||||
|
Instructions.jal -> RegWriteSource.NextInstructionAddress,
|
||||||
|
Instructions.jalr -> RegWriteSource.NextInstructionAddress,
|
||||||
|
Instructions.csr -> RegWriteSource.CSR
|
||||||
|
)
|
||||||
|
)
|
||||||
|
io.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.reg_write_address := io.instruction(11, 7)
|
||||||
|
io.csr_reg_address := io.instruction(31,20)
|
||||||
|
io.csr_reg_write_enable := (opcode === Instructions.csr) && (
|
||||||
|
funct3 === InstructionsTypeCSR.csrrw || funct3 === InstructionsTypeCSR.csrrwi ||
|
||||||
|
funct3 === InstructionsTypeCSR.csrrs || funct3 === InstructionsTypeCSR.csrrsi ||
|
||||||
|
funct3 === InstructionsTypeCSR.csrrc || funct3 === InstructionsTypeCSR.csrrci
|
||||||
|
)
|
||||||
|
}
|
||||||
53
lab2/朱梓涵24325356/scala/riscv/core/InstructionFetch.scala
Normal file
53
lab2/朱梓涵24325356/scala/riscv/core/InstructionFetch.scala
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// Copyright 2021 Howard Lau
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package riscv.core
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import riscv.Parameters
|
||||||
|
|
||||||
|
object ProgramCounter {
|
||||||
|
val EntryAddress = Parameters.EntryAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
class InstructionFetch extends Module {
|
||||||
|
val io = IO(new Bundle {
|
||||||
|
val jump_flag_id = Input(Bool())
|
||||||
|
val jump_address_id = Input(UInt(Parameters.AddrWidth))
|
||||||
|
val instruction_read_data = Input(UInt(Parameters.DataWidth))
|
||||||
|
val interrupt_assert = Input(Bool())
|
||||||
|
val interrupt_handler_address = Input(UInt(Parameters.AddrWidth))
|
||||||
|
val instruction_valid = Input(Bool())
|
||||||
|
|
||||||
|
val instruction_address = Output(UInt(Parameters.AddrWidth))
|
||||||
|
val instruction = Output(UInt(Parameters.InstructionWidth))
|
||||||
|
|
||||||
|
})
|
||||||
|
val pc = RegInit(ProgramCounter.EntryAddress)
|
||||||
|
|
||||||
|
when(io.instruction_valid) {
|
||||||
|
when(io.interrupt_assert){
|
||||||
|
pc := io.interrupt_handler_address
|
||||||
|
}.elsewhen(io.jump_flag_id){
|
||||||
|
pc := io.jump_address_id
|
||||||
|
}.otherwise {
|
||||||
|
pc := pc + 4.U
|
||||||
|
}
|
||||||
|
io.instruction := io.instruction_read_data
|
||||||
|
}.otherwise{
|
||||||
|
pc := pc
|
||||||
|
io.instruction := 0x00000013.U
|
||||||
|
}
|
||||||
|
io.instruction_address := pc
|
||||||
|
}
|
||||||
105
lab2/朱梓涵24325356/scala/riscv/core/MemoryAccess.scala
Normal file
105
lab2/朱梓涵24325356/scala/riscv/core/MemoryAccess.scala
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util._
|
||||||
|
import peripheral.RAMBundle
|
||||||
|
import riscv.Parameters
|
||||||
|
|
||||||
|
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 wb_memory_read_data = Output(UInt(Parameters.DataWidth))
|
||||||
|
|
||||||
|
val memory_bundle = Flipped(new RAMBundle)
|
||||||
|
})
|
||||||
|
val mem_address_index = io.alu_result(log2Up(Parameters.WordSize) - 1, 0).asUInt
|
||||||
|
|
||||||
|
io.memory_bundle.write_enable := false.B
|
||||||
|
io.memory_bundle.write_data := 0.U
|
||||||
|
io.memory_bundle.address := io.alu_result
|
||||||
|
io.memory_bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B))
|
||||||
|
io.wb_memory_read_data := 0.U
|
||||||
|
|
||||||
|
when(io.memory_read_enable) {
|
||||||
|
val data = io.memory_bundle.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
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}.elsewhen(io.memory_write_enable) {
|
||||||
|
io.memory_bundle.write_data := io.reg2_data
|
||||||
|
io.memory_bundle.write_enable := true.B
|
||||||
|
io.memory_bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B))
|
||||||
|
when(io.funct3 === InstructionsTypeS.sb) {
|
||||||
|
io.memory_bundle.write_strobe(mem_address_index) := true.B
|
||||||
|
io.memory_bundle.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.memory_bundle.write_strobe(i) := true.B
|
||||||
|
}
|
||||||
|
io.memory_bundle.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0)
|
||||||
|
}.otherwise {
|
||||||
|
for (i <- Parameters.WordSize / 2 until Parameters.WordSize) {
|
||||||
|
io.memory_bundle.write_strobe(i) := true.B
|
||||||
|
}
|
||||||
|
io.memory_bundle.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.memory_bundle.write_strobe(i) := true.B
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
95
lab2/朱梓涵24325356/scala/riscv/core/RegisterFile.scala
Normal file
95
lab2/朱梓涵24325356/scala/riscv/core/RegisterFile.scala
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
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 = RegInit(VecInit(Seq.fill(Parameters.PhysicalRegisters)(0.U(Parameters.DataWidth))))
|
||||||
|
|
||||||
|
when(!reset.asBool) {
|
||||||
|
when(io.write_enable && io.write_address =/= 0.U) {
|
||||||
|
registers(io.write_address) := io.write_data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
io.read_data1 := Mux(
|
||||||
|
io.read_address1 === 0.U,
|
||||||
|
0.U,
|
||||||
|
registers(io.read_address1)
|
||||||
|
)
|
||||||
|
|
||||||
|
io.read_data2 := Mux(
|
||||||
|
io.read_address2 === 0.U,
|
||||||
|
0.U,
|
||||||
|
registers(io.read_address2)
|
||||||
|
)
|
||||||
|
|
||||||
|
io.debug_read_data := Mux(
|
||||||
|
io.debug_read_address === 0.U,
|
||||||
|
0.U,
|
||||||
|
registers(io.debug_read_address)
|
||||||
|
)
|
||||||
|
// 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
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
|
||||||
|
}
|
||||||
39
lab2/朱梓涵24325356/scala/riscv/core/WriteBack.scala
Normal file
39
lab2/朱梓涵24325356/scala/riscv/core/WriteBack.scala
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
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),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user