实验报告检查

This commit is contained in:
2025-12-21 23:11:21 +08:00
parent 078b2c0b37
commit 52ecd7743b
85 changed files with 8477 additions and 16 deletions

View File

@@ -0,0 +1,69 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core
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
}
}
}

View File

@@ -0,0 +1,87 @@
// 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.core.threestage.{InstructionTypes, Instructions, InstructionsTypeI, InstructionsTypeR}
class ALUControl extends Module {
val io = IO(new Bundle {
val opcode = Input(UInt(7.W))
val funct3 = Input(UInt(3.W))
val funct7 = Input(UInt(7.W))
val alu_funct = Output(ALUFunctions())
})
io.alu_funct := ALUFunctions.zero
switch(io.opcode) {
is(InstructionTypes.I) {
io.alu_funct := MuxLookup(
io.funct3,
ALUFunctions.zero,
IndexedSeq(
InstructionsTypeI.addi -> ALUFunctions.add,
InstructionsTypeI.slli -> ALUFunctions.sll,
InstructionsTypeI.slti -> ALUFunctions.slt,
InstructionsTypeI.sltiu -> ALUFunctions.sltu,
InstructionsTypeI.xori -> ALUFunctions.xor,
InstructionsTypeI.ori -> ALUFunctions.or,
InstructionsTypeI.andi -> ALUFunctions.and,
InstructionsTypeI.sri -> Mux(io.funct7(5), ALUFunctions.sra, ALUFunctions.srl)
),
)
}
is(InstructionTypes.RM) {
io.alu_funct := MuxLookup(
io.funct3,
ALUFunctions.zero,
IndexedSeq(
InstructionsTypeR.add_sub -> Mux(io.funct7(5), ALUFunctions.sub, ALUFunctions.add),
InstructionsTypeR.sll -> ALUFunctions.sll,
InstructionsTypeR.slt -> ALUFunctions.slt,
InstructionsTypeR.sltu -> ALUFunctions.sltu,
InstructionsTypeR.xor -> ALUFunctions.xor,
InstructionsTypeR.or -> ALUFunctions.or,
InstructionsTypeR.and -> ALUFunctions.and,
InstructionsTypeR.sr -> Mux(io.funct7(5), ALUFunctions.sra, ALUFunctions.srl)
),
)
}
is(InstructionTypes.B) {
io.alu_funct := ALUFunctions.add
}
is(InstructionTypes.L) {
io.alu_funct := ALUFunctions.add
}
is(InstructionTypes.S) {
io.alu_funct := ALUFunctions.add
}
is(Instructions.jal) {
io.alu_funct := ALUFunctions.add
}
is(Instructions.jalr) {
io.alu_funct := ALUFunctions.add
}
is(Instructions.lui) {
io.alu_funct := ALUFunctions.add
}
is(Instructions.auipc) {
io.alu_funct := ALUFunctions.add
}
}
}

View File

@@ -0,0 +1,40 @@
// Copyright 2022 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core
import chisel3._
import riscv.ImplementationType
import riscv.core.fivestage_final.{CPU => FiveStageCPUFinal}
import riscv.core.fivestage_forward.{CPU => FiveStageCPUForward}
import riscv.core.fivestage_stall.{CPU => FiveStageCPUStall}
import riscv.core.threestage.{CPU => ThreeStageCPU}
class CPU(val implementation: Int = ImplementationType.FiveStageFinal) extends Module {
val io = IO(new CPUBundle)
implementation match {
case ImplementationType.ThreeStage =>
val cpu = Module(new ThreeStageCPU)
cpu.io <> io
case ImplementationType.FiveStageStall =>
val cpu = Module(new FiveStageCPUStall)
cpu.io <> io
case ImplementationType.FiveStageForward =>
val cpu = Module(new FiveStageCPUForward)
cpu.io <> io
case _ =>
val cpu = Module(new FiveStageCPUFinal)
cpu.io <> io
}
}

View File

@@ -0,0 +1,30 @@
// Copyright 2022 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core
import chisel3._
import peripheral.RAMBundle
import riscv.Parameters
class CPUBundle extends Bundle {
val instruction_address = Output(UInt(Parameters.AddrWidth))
val instruction = Input(UInt(Parameters.DataWidth))
val instruction_valid = Input(Bool())
val memory_bundle = Flipped(new RAMBundle)
val device_select = Output(UInt(Parameters.SlaveDeviceCountBits.W))
val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth))
val debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val debug_read_data = Output(UInt(Parameters.DataWidth))
}

View File

@@ -0,0 +1,99 @@
// 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
import riscv.core.threestage.CSRDirectAccessBundle
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_ex = Input(Bool())
val reg_write_address_ex = Input(UInt(Parameters.CSRRegisterAddrWidth))
val reg_write_data_ex = Input(UInt(Parameters.DataWidth))
val id_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.id_reg_read_data := MuxLookup(io.reg_read_address_id, 0.U, regLUT)
io.clint_access_bundle.mstatus := Mux(io.reg_write_enable_ex && io.reg_write_address_ex === CSRRegister.MSTATUS, io.reg_write_data_ex, mstatus)
io.clint_access_bundle.mtvec := Mux(io.reg_write_enable_ex && io.reg_write_address_ex === CSRRegister.MTVEC, io.reg_write_data_ex, mtvec)
io.clint_access_bundle.mcause := Mux(io.reg_write_enable_ex && io.reg_write_address_ex === CSRRegister.MCAUSE, io.reg_write_data_ex, mcause)
io.clint_access_bundle.mepc := Mux(io.reg_write_enable_ex && io.reg_write_address_ex === CSRRegister.MEPC, io.reg_write_data_ex, mepc)
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_ex) {
when(io.reg_write_address_ex === CSRRegister.MSTATUS) {
mstatus := io.reg_write_data_ex
}.elsewhen(io.reg_write_address_ex === CSRRegister.MEPC) {
mepc := io.reg_write_data_ex
}.elsewhen(io.reg_write_address_ex === CSRRegister.MCAUSE) {
mcause := io.reg_write_data_ex
}
}
when(io.reg_write_enable_ex) {
when(io.reg_write_address_ex === CSRRegister.MIE) {
mie := io.reg_write_data_ex
}.elsewhen(io.reg_write_address_ex === CSRRegister.MTVEC) {
mtvec := io.reg_write_data_ex
}.elsewhen(io.reg_write_address_ex === CSRRegister.MSCRATCH) {
mscratch := io.reg_write_data_ex
}
}
}

View File

@@ -0,0 +1,39 @@
// 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
class PipelineRegister(width: Int = Parameters.DataBits, defaultValue: UInt = 0.U) extends Module {
val io = IO(new Bundle {
val stall = Input(Bool())
val flush = Input(Bool())
val in = Input(UInt(width.W))
val out = Output(UInt(width.W))
})
// Lab3(PipelineRegister)
val register = RegInit(defaultValue)
when(io.flush) {
register := defaultValue
}.elsewhen(io.stall) {
}.otherwise {
register := io.in
}
io.out := register
// Lab3(PipelineRegister) End
}

View File

@@ -0,0 +1,78 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core
import chisel3._
import chisel3.util._
import riscv.Parameters
object Registers extends Enumeration {
type Register = Value
val zero,
ra, sp, gp, tp,
t0, t1, t2, fp,
s1,
a0, a1, a2, a3, a4, a5, a6, a7,
s2, s3, s4, s5, s6, s7, s8, s9, s10, s11,
t3, t4, t5, t6 = Value
}
class RegisterFile extends Module {
val io = IO(new Bundle {
val write_enable = Input(Bool())
val write_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val write_data = Input(UInt(Parameters.DataWidth))
val read_address1 = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val read_address2 = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val read_data1 = Output(UInt(Parameters.DataWidth))
val read_data2 = Output(UInt(Parameters.DataWidth))
val debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val debug_read_data = Output(UInt(Parameters.DataWidth))
})
val registers = Reg(Vec(Parameters.PhysicalRegisters, UInt(Parameters.DataWidth)))
when(!reset.asBool) {
when(io.write_enable && io.write_address =/= 0.U) {
registers(io.write_address) := io.write_data
}
}
io.read_data1 := MuxCase(
registers(io.read_address1),
IndexedSeq(
(io.read_address1 === 0.U) -> 0.U,
(io.read_address1 === io.write_address && io.write_enable) -> io.write_data
)
)
io.read_data2 := MuxCase(
registers(io.read_address2),
IndexedSeq(
(io.read_address2 === 0.U) -> 0.U,
(io.read_address2 === io.write_address && io.write_enable) -> io.write_data
)
)
io.debug_read_data := MuxCase(
registers(io.debug_read_address),
IndexedSeq(
(io.debug_read_address === 0.U) -> 0.U,
(io.debug_read_address === io.write_address && io.write_enable) -> io.write_data
)
)
}

View File

@@ -0,0 +1,101 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_final
import chisel3._
import chisel3.util.MuxLookup
import riscv.Parameters
object InterruptStatus {
val None = 0x0.U(8.W)
val Timer0 = 0x1.U(8.W)
val Ret = 0xFF.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 {
val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth))
val instruction_id = Input(UInt(Parameters.InstructionWidth))
val instruction_address_if = Input(UInt(Parameters.AddrWidth))
val jump_flag = Input(Bool())
val jump_address = Input(UInt(Parameters.AddrWidth))
val id_interrupt_handler_address = Output(UInt(Parameters.AddrWidth))
val id_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_if,
)
val mstatus_disable_interrupt = io.csr_bundle.mstatus(31, 4) ## 0.U(1.W) ## io.csr_bundle.mstatus(2, 0)
val mstatus_recover_interrupt = io.csr_bundle.mstatus(31, 4) ## io.csr_bundle.mstatus(7) ## io.csr_bundle.mstatus(2, 0)
when(io.instruction_id === InstructionsEnv.ecall || io.instruction_id === InstructionsEnv.ebreak) {
io.csr_bundle.mstatus_write_data := mstatus_disable_interrupt
io.csr_bundle.mepc_write_data := instruction_address
io.csr_bundle.mcause_write_data := MuxLookup(
io.instruction_id,
10.U,
IndexedSeq(
InstructionsEnv.ecall -> 11.U,
InstructionsEnv.ebreak -> 3.U,
)
)
io.csr_bundle.direct_write_enable := true.B
io.id_interrupt_assert := true.B
io.id_interrupt_handler_address := io.csr_bundle.mtvec
}.elsewhen(io.interrupt_flag =/= InterruptStatus.None && interrupt_enable) {
io.csr_bundle.mstatus_write_data := mstatus_disable_interrupt
io.csr_bundle.mepc_write_data := instruction_address
io.csr_bundle.mcause_write_data := Mux(io.interrupt_flag(0), 0x80000007L.U, 0x8000000BL.U)
io.csr_bundle.direct_write_enable := true.B
io.id_interrupt_assert := true.B
io.id_interrupt_handler_address := io.csr_bundle.mtvec
}.elsewhen(io.instruction_id === InstructionsRet.mret) {
io.csr_bundle.mstatus_write_data := mstatus_recover_interrupt
io.csr_bundle.mepc_write_data := io.csr_bundle.mepc
io.csr_bundle.mcause_write_data := io.csr_bundle.mcause
io.csr_bundle.direct_write_enable := true.B
io.id_interrupt_assert := true.B
io.id_interrupt_handler_address := io.csr_bundle.mepc
}.otherwise {
io.csr_bundle.mstatus_write_data := io.csr_bundle.mstatus
io.csr_bundle.mepc_write_data := io.csr_bundle.mepc
io.csr_bundle.mcause_write_data := io.csr_bundle.mcause
io.csr_bundle.direct_write_enable := false.B
io.id_interrupt_assert := false.B
io.id_interrupt_handler_address := 0.U
}
}

View File

@@ -0,0 +1,169 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_final
import chisel3._
import riscv.Parameters
import riscv.core.{CPUBundle, CSR, RegisterFile}
class CPU extends Module {
val io = IO(new CPUBundle)
val ctrl = Module(new Control)
val regs = Module(new RegisterFile)
val inst_fetch = Module(new InstructionFetch)
val if2id = Module(new IF2ID)
val id = Module(new InstructionDecode)
val id2ex = Module(new ID2EX)
val ex = Module(new Execute)
val ex2mem = Module(new EX2MEM)
val mem = Module(new MemoryAccess)
val mem2wb = Module(new MEM2WB)
val wb = Module(new WriteBack)
val forwarding = Module(new Forwarding)
val clint = Module(new CLINT)
val csr_regs = Module(new CSR)
ctrl.io.jump_flag := id.io.if_jump_flag
ctrl.io.jump_instruction_id := id.io.ctrl_jump_instruction
ctrl.io.rs1_id := id.io.regs_reg1_read_address
ctrl.io.rs2_id := id.io.regs_reg2_read_address
ctrl.io.memory_read_enable_ex := id2ex.io.output_memory_read_enable
ctrl.io.rd_ex := id2ex.io.output_regs_write_address
ctrl.io.memory_read_enable_mem := ex2mem.io.output_memory_read_enable
ctrl.io.rd_mem := ex2mem.io.output_regs_write_address
regs.io.write_enable := mem2wb.io.output_regs_write_enable
regs.io.write_address := mem2wb.io.output_regs_write_address
regs.io.write_data := wb.io.regs_write_data
regs.io.read_address1 := id.io.regs_reg1_read_address
regs.io.read_address2 := id.io.regs_reg2_read_address
regs.io.debug_read_address := io.debug_read_address
io.debug_read_data := regs.io.debug_read_data
io.instruction_address := inst_fetch.io.instruction_address
inst_fetch.io.stall_flag_ctrl := ctrl.io.pc_stall
inst_fetch.io.jump_flag_id := id.io.if_jump_flag
inst_fetch.io.jump_address_id := id.io.if_jump_address
inst_fetch.io.rom_instruction := io.instruction
inst_fetch.io.instruction_valid := io.instruction_valid
if2id.io.stall := ctrl.io.if2id_stall
if2id.io.flush := ctrl.io.if2id_flush
if2id.io.instruction := inst_fetch.io.id_instruction
if2id.io.instruction_address := inst_fetch.io.instruction_address
if2id.io.interrupt_flag := io.interrupt_flag
id.io.instruction := if2id.io.output_instruction
id.io.instruction_address := if2id.io.output_instruction_address
id.io.reg1_data := regs.io.read_data1
id.io.reg2_data := regs.io.read_data2
id.io.forward_from_mem := mem.io.forward_data
id.io.forward_from_wb := wb.io.regs_write_data
id.io.reg1_forward := forwarding.io.reg1_forward_id
id.io.reg2_forward := forwarding.io.reg2_forward_id
id.io.interrupt_assert := clint.io.id_interrupt_assert
id.io.interrupt_handler_address := clint.io.id_interrupt_handler_address
id2ex.io.flush := ctrl.io.id2ex_flush
id2ex.io.instruction := if2id.io.output_instruction
id2ex.io.instruction_address := if2id.io.output_instruction_address
id2ex.io.reg1_data := regs.io.read_data1
id2ex.io.reg2_data := regs.io.read_data2
id2ex.io.regs_reg1_read_address := id.io.regs_reg1_read_address
id2ex.io.regs_reg2_read_address := id.io.regs_reg2_read_address
id2ex.io.regs_write_enable := id.io.ex_reg_write_enable
id2ex.io.regs_write_address := id.io.ex_reg_write_address
id2ex.io.regs_write_source := id.io.ex_reg_write_source
id2ex.io.immediate := id.io.ex_immediate
id2ex.io.aluop1_source := id.io.ex_aluop1_source
id2ex.io.aluop2_source := id.io.ex_aluop2_source
id2ex.io.csr_write_enable := id.io.ex_csr_write_enable
id2ex.io.csr_address := id.io.ex_csr_address
id2ex.io.memory_read_enable := id.io.ex_memory_read_enable
id2ex.io.memory_write_enable := id.io.ex_memory_write_enable
id2ex.io.csr_read_data := csr_regs.io.id_reg_read_data
ex.io.instruction := id2ex.io.output_instruction
ex.io.instruction_address := id2ex.io.output_instruction_address
ex.io.reg1_data := id2ex.io.output_reg1_data
ex.io.reg2_data := id2ex.io.output_reg2_data
ex.io.immediate := id2ex.io.output_immediate
ex.io.aluop1_source := id2ex.io.output_aluop1_source
ex.io.aluop2_source := id2ex.io.output_aluop2_source
ex.io.csr_read_data := id2ex.io.output_csr_read_data
ex.io.forward_from_mem := mem.io.forward_data
ex.io.forward_from_wb := wb.io.regs_write_data
ex.io.reg1_forward := forwarding.io.reg1_forward_ex
ex.io.reg2_forward := forwarding.io.reg2_forward_ex
ex2mem.io.regs_write_enable := id2ex.io.output_regs_write_enable
ex2mem.io.regs_write_source := id2ex.io.output_regs_write_source
ex2mem.io.regs_write_address := id2ex.io.output_regs_write_address
ex2mem.io.instruction_address := id2ex.io.output_instruction_address
ex2mem.io.funct3 := id2ex.io.output_instruction(14, 12)
ex2mem.io.reg2_data := ex.io.mem_reg2_data
ex2mem.io.memory_read_enable := id2ex.io.output_memory_read_enable
ex2mem.io.memory_write_enable := id2ex.io.output_memory_write_enable
ex2mem.io.alu_result := ex.io.mem_alu_result
ex2mem.io.csr_read_data := id2ex.io.output_csr_read_data
mem.io.alu_result := ex2mem.io.output_alu_result
mem.io.reg2_data := ex2mem.io.output_reg2_data
mem.io.memory_read_enable := ex2mem.io.output_memory_read_enable
mem.io.memory_write_enable := ex2mem.io.output_memory_write_enable
mem.io.funct3 := ex2mem.io.output_funct3
mem.io.regs_write_source := ex2mem.io.output_regs_write_source
mem.io.csr_read_data := ex2mem.io.output_csr_read_data
io.device_select := mem.io.bundle.address(Parameters.AddrBits - 1, Parameters.AddrBits - Parameters.SlaveDeviceCountBits)
io.memory_bundle <> mem.io.bundle
io.memory_bundle.address := 0.U(Parameters.SlaveDeviceCountBits.W) ## mem.io.bundle.address(Parameters.AddrBits - 1 - Parameters.SlaveDeviceCountBits, 0)
mem2wb.io.instruction_address := ex2mem.io.output_instruction_address
mem2wb.io.alu_result := ex2mem.io.output_alu_result
mem2wb.io.regs_write_enable := ex2mem.io.output_regs_write_enable
mem2wb.io.regs_write_source := ex2mem.io.output_regs_write_source
mem2wb.io.regs_write_address := ex2mem.io.output_regs_write_address
mem2wb.io.memory_read_data := mem.io.wb_memory_read_data
mem2wb.io.csr_read_data := ex2mem.io.output_csr_read_data
wb.io.instruction_address := mem2wb.io.output_instruction_address
wb.io.alu_result := mem2wb.io.output_alu_result
wb.io.memory_read_data := mem2wb.io.output_memory_read_data
wb.io.regs_write_source := mem2wb.io.output_regs_write_source
wb.io.csr_read_data := mem2wb.io.output_csr_read_data
forwarding.io.rs1_id := id.io.regs_reg1_read_address
forwarding.io.rs2_id := id.io.regs_reg2_read_address
forwarding.io.rs1_ex := id2ex.io.output_regs_reg1_read_address
forwarding.io.rs2_ex := id2ex.io.output_regs_reg2_read_address
forwarding.io.rd_mem := ex2mem.io.output_regs_write_address
forwarding.io.reg_write_enable_mem := ex2mem.io.output_regs_write_enable
forwarding.io.rd_wb := mem2wb.io.output_regs_write_address
forwarding.io.reg_write_enable_wb := mem2wb.io.output_regs_write_enable
clint.io.instruction_address_if := inst_fetch.io.instruction_address
clint.io.instruction_id := if2id.io.output_instruction
clint.io.jump_flag := id.io.clint_jump_flag
clint.io.jump_address := id.io.clint_jump_address
clint.io.interrupt_flag := if2id.io.output_interrupt_flag
clint.io.csr_bundle <> csr_regs.io.clint_access_bundle
csr_regs.io.reg_read_address_id := id.io.ex_csr_address
csr_regs.io.reg_write_enable_ex := id2ex.io.output_csr_write_enable
csr_regs.io.reg_write_address_ex := id2ex.io.output_csr_address
csr_regs.io.reg_write_data_ex := ex.io.csr_write_data
}

View File

@@ -0,0 +1,62 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_final
import chisel3._
import riscv.Parameters
class Control extends Module {
val io = IO(new Bundle {
val jump_flag = Input(Bool())
val jump_instruction_id = Input(Bool())
val rs1_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val rs2_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val memory_read_enable_ex = Input(Bool())
val rd_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val memory_read_enable_mem = Input(Bool())
val rd_mem = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val if2id_flush = Output(Bool())
val id2ex_flush = Output(Bool())
val pc_stall = Output(Bool())
val if2id_stall = Output(Bool())
})
// Lab3(Final)
val stall = Wire(Bool())
val load_use_hazard = io.memory_read_enable_ex && io.rd_ex =/= 0.U &&
(io.rd_ex === io.rs1_id || io.rd_ex === io.rs2_id)
val id_jump_needs_ex_alu = io.jump_instruction_id && io.rd_ex =/= 0.U &&
!io.memory_read_enable_ex &&
(io.rd_ex === io.rs1_id || io.rd_ex === io.rs2_id)
val id_jump_needs_mem_load = io.jump_instruction_id && io.memory_read_enable_mem && io.rd_mem =/= 0.U &&
(io.rd_mem === io.rs1_id || io.rd_mem === io.rs2_id)
stall := load_use_hazard || id_jump_needs_ex_alu || id_jump_needs_mem_load
val flush = io.jump_flag && !stall
io.pc_stall := stall
io.if2id_stall := stall
io.if2id_flush := flush
io.id2ex_flush := stall
// Lab3(Final) End
}

View File

@@ -0,0 +1,108 @@
// Copyright 2022 Canbin Huang
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_final
import chisel3._
import riscv.Parameters
import riscv.core.PipelineRegister
class EX2MEM extends Module {
val io = IO(new Bundle() {
val regs_write_enable = Input(Bool())
val regs_write_source = Input(UInt(2.W))
val regs_write_address = Input(UInt(Parameters.AddrWidth))
val instruction_address = Input(UInt(Parameters.AddrWidth))
val funct3 = Input(UInt(3.W))
val reg2_data = Input(UInt(Parameters.DataWidth))
val memory_read_enable = Input(Bool())
val memory_write_enable = Input(Bool())
val alu_result = Input(UInt(Parameters.DataWidth))
val csr_read_data = Input(UInt(Parameters.DataWidth))
val output_regs_write_enable = Output(Bool())
val output_regs_write_source = Output(UInt(2.W))
val output_regs_write_address = Output(UInt(Parameters.AddrWidth))
val output_instruction_address = Output(UInt(Parameters.AddrWidth))
val output_funct3 = Output(UInt(Parameters.DataWidth))
val output_reg2_data = Output(UInt(Parameters.DataWidth))
val output_memory_read_enable = Output(Bool())
val output_memory_write_enable = Output(Bool())
val output_alu_result = Output(UInt(Parameters.DataWidth))
val output_csr_read_data = Output(UInt(Parameters.DataWidth))
})
val stall = false.B
val flush = false.B
val regs_write_enable = Module(new PipelineRegister(1))
regs_write_enable.io.in := io.regs_write_enable
regs_write_enable.io.stall := stall
regs_write_enable.io.flush := flush
io.output_regs_write_enable := regs_write_enable.io.out
val regs_write_source = Module(new PipelineRegister(2))
regs_write_source.io.in := io.regs_write_source
regs_write_source.io.stall := stall
regs_write_source.io.flush := flush
io.output_regs_write_source := regs_write_source.io.out
val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits))
regs_write_address.io.in := io.regs_write_address
regs_write_address.io.stall := stall
regs_write_address.io.flush := flush
io.output_regs_write_address := regs_write_address.io.out
val instruction_address = Module(new PipelineRegister(Parameters.AddrBits))
instruction_address.io.in := io.instruction_address
instruction_address.io.stall := stall
instruction_address.io.flush := flush
io.output_instruction_address := instruction_address.io.out
val funct3 = Module(new PipelineRegister(3))
funct3.io.in := io.funct3
funct3.io.stall := stall
funct3.io.flush := flush
io.output_funct3 := funct3.io.out
val reg2_data = Module(new PipelineRegister())
reg2_data.io.in := io.reg2_data
reg2_data.io.stall := stall
reg2_data.io.flush := flush
io.output_reg2_data := reg2_data.io.out
val alu_result = Module(new PipelineRegister())
alu_result.io.in := io.alu_result
alu_result.io.stall := stall
alu_result.io.flush := flush
io.output_alu_result := alu_result.io.out
val memory_read_enable = Module(new PipelineRegister(1))
memory_read_enable.io.in := io.memory_read_enable
memory_read_enable.io.stall := stall
memory_read_enable.io.flush := flush
io.output_memory_read_enable := memory_read_enable.io.out
val memory_write_enable = Module(new PipelineRegister(1))
memory_write_enable.io.in := io.memory_write_enable
memory_write_enable.io.stall := stall
memory_write_enable.io.flush := flush
io.output_memory_write_enable := memory_write_enable.io.out
val csr_read_data = Module(new PipelineRegister())
csr_read_data.io.in := io.csr_read_data
csr_read_data.io.stall := stall
csr_read_data.io.flush := flush
io.output_csr_read_data := csr_read_data.io.out
}

View 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.fivestage_final
import chisel3._
import chisel3.util._
import riscv.Parameters
import riscv.core.{ALU, ALUControl}
class Execute extends Module {
val io = IO(new Bundle {
val instruction = Input(UInt(Parameters.InstructionWidth))
val instruction_address = Input(UInt(Parameters.AddrWidth))
val reg1_data = Input(UInt(Parameters.DataWidth))
val reg2_data = Input(UInt(Parameters.DataWidth))
val immediate = Input(UInt(Parameters.DataWidth))
val aluop1_source = Input(UInt(1.W))
val aluop2_source = Input(UInt(1.W))
val csr_read_data = Input(UInt(Parameters.DataWidth))
val forward_from_mem = Input(UInt(Parameters.DataWidth))
val forward_from_wb = Input(UInt(Parameters.DataWidth))
val reg1_forward = Input(UInt(2.W))
val reg2_forward = Input(UInt(2.W))
val mem_alu_result = Output(UInt(Parameters.DataWidth))
val mem_reg2_data = Output(UInt(Parameters.DataWidth))
val csr_write_data = Output(UInt(Parameters.DataWidth))
})
val opcode = io.instruction(6, 0)
val funct3 = io.instruction(14, 12)
val funct7 = io.instruction(31, 25)
val uimm = io.instruction(19, 15)
val alu = Module(new ALU)
val alu_ctrl = Module(new ALUControl)
alu_ctrl.io.opcode := opcode
alu_ctrl.io.funct3 := funct3
alu_ctrl.io.funct7 := funct7
alu.io.func := alu_ctrl.io.alu_funct
val reg1_data = MuxLookup(
io.reg1_forward,
io.reg1_data,
IndexedSeq(
ForwardingType.ForwardFromMEM -> io.forward_from_mem,
ForwardingType.ForwardFromWB -> io.forward_from_wb
)
)
alu.io.op1 := Mux(
io.aluop1_source === ALUOp1Source.InstructionAddress,
io.instruction_address,
reg1_data
)
val reg2_data = MuxLookup(
io.reg2_forward,
io.reg2_data,
IndexedSeq(
ForwardingType.ForwardFromMEM -> io.forward_from_mem,
ForwardingType.ForwardFromWB -> io.forward_from_wb
)
)
alu.io.op2 := Mux(
io.aluop2_source === ALUOp2Source.Immediate,
io.immediate,
reg2_data
)
io.mem_alu_result := alu.io.result
io.mem_reg2_data := reg2_data
io.csr_write_data := MuxLookup(funct3, 0.U, IndexedSeq(
InstructionsTypeCSR.csrrw -> reg1_data,
InstructionsTypeCSR.csrrc -> io.csr_read_data.&((~reg1_data).asUInt),
InstructionsTypeCSR.csrrs -> io.csr_read_data.|(reg1_data),
InstructionsTypeCSR.csrrwi -> Cat(0.U(27.W), uimm),
InstructionsTypeCSR.csrrci -> io.csr_read_data.&((~Cat(0.U(27.W), uimm)).asUInt),
InstructionsTypeCSR.csrrsi -> io.csr_read_data.|(Cat(0.U(27.W), uimm)),
))
}

View File

@@ -0,0 +1,67 @@
// Copyright 2022 Canbin Huang
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_final
import chisel3._
import riscv.Parameters
object ForwardingType {
val NoForward = 0.U(2.W)
val ForwardFromMEM = 1.U(2.W)
val ForwardFromWB = 2.U(2.W)
}
class Forwarding extends Module {
val io = IO(new Bundle() {
val rs1_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val rs2_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val rs1_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val rs2_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val rd_mem = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val reg_write_enable_mem = Input(Bool())
val rd_wb = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val reg_write_enable_wb = Input(Bool())
val reg1_forward_id = Output(UInt(2.W))
val reg2_forward_id = Output(UInt(2.W))
val reg1_forward_ex = Output(UInt(2.W))
val reg2_forward_ex = Output(UInt(2.W))
})
// Lab3(Final)
val ex_mem_hazard_rs1 = io.reg_write_enable_mem && io.rd_mem =/= 0.U && (io.rd_mem === io.rs1_ex)
val ex_mem_hazard_rs2 = io.reg_write_enable_mem && io.rd_mem =/= 0.U && (io.rd_mem === io.rs2_ex)
val ex_wb_hazard_rs1 = io.reg_write_enable_wb && io.rd_wb =/= 0.U && (io.rd_wb === io.rs1_ex)
val ex_wb_hazard_rs2 = io.reg_write_enable_wb && io.rd_wb =/= 0.U && (io.rd_wb === io.rs2_ex)
io.reg1_forward_ex := Mux(ex_mem_hazard_rs1, ForwardingType.ForwardFromMEM,
Mux(ex_wb_hazard_rs1, ForwardingType.ForwardFromWB, ForwardingType.NoForward))
io.reg2_forward_ex := Mux(ex_mem_hazard_rs2, ForwardingType.ForwardFromMEM,
Mux(ex_wb_hazard_rs2, ForwardingType.ForwardFromWB, ForwardingType.NoForward))
val id_mem_hazard_rs1 = io.reg_write_enable_mem && io.rd_mem =/= 0.U && (io.rd_mem === io.rs1_id)
val id_mem_hazard_rs2 = io.reg_write_enable_mem && io.rd_mem =/= 0.U && (io.rd_mem === io.rs2_id)
val id_wb_hazard_rs1 = io.reg_write_enable_wb && io.rd_wb =/= 0.U && !id_mem_hazard_rs1 && (io.rd_wb === io.rs1_id)
val id_wb_hazard_rs2 = io.reg_write_enable_wb && io.rd_wb =/= 0.U && !id_mem_hazard_rs2 && (io.rd_wb === io.rs2_id)
io.reg1_forward_id := Mux(id_mem_hazard_rs1, ForwardingType.ForwardFromMEM,
Mux(id_wb_hazard_rs1, ForwardingType.ForwardFromWB, ForwardingType.NoForward))
io.reg2_forward_id := Mux(id_mem_hazard_rs2, ForwardingType.ForwardFromMEM,
Mux(id_wb_hazard_rs2, ForwardingType.ForwardFromWB, ForwardingType.NoForward))
// Lab3(Final) End
}

View File

@@ -0,0 +1,163 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_final
import chisel3._
import riscv.Parameters
import riscv.core.PipelineRegister
class ID2EX extends Module {
val io = IO(new Bundle {
val flush = Input(Bool())
val instruction = Input(UInt(Parameters.InstructionWidth))
val instruction_address = Input(UInt(Parameters.AddrWidth))
val regs_reg1_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val regs_reg2_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val regs_write_enable = Input(Bool())
val regs_write_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val regs_write_source = Input(UInt(2.W))
val reg1_data = Input(UInt(Parameters.DataWidth))
val reg2_data = Input(UInt(Parameters.DataWidth))
val immediate = Input(UInt(Parameters.DataWidth))
val aluop1_source = Input(UInt(1.W))
val aluop2_source = Input(UInt(1.W))
val csr_write_enable = Input(Bool())
val csr_address = Input(UInt(Parameters.CSRRegisterAddrWidth))
val memory_read_enable = Input(Bool())
val memory_write_enable = Input(Bool())
val csr_read_data = Input(UInt(Parameters.DataWidth))
val output_instruction = Output(UInt(Parameters.DataWidth))
val output_instruction_address = Output(UInt(Parameters.AddrWidth))
val output_regs_reg1_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
val output_regs_reg2_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
val output_regs_write_enable = Output(Bool())
val output_regs_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
val output_regs_write_source = Output(UInt(2.W))
val output_reg1_data = Output(UInt(Parameters.DataWidth))
val output_reg2_data = Output(UInt(Parameters.DataWidth))
val output_immediate = Output(UInt(Parameters.DataWidth))
val output_aluop1_source = Output(UInt(1.W))
val output_aluop2_source = Output(UInt(1.W))
val output_csr_write_enable = Output(Bool())
val output_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth))
val output_memory_read_enable = Output(Bool())
val output_memory_write_enable = Output(Bool())
val output_csr_read_data = Output(UInt(Parameters.DataWidth))
})
val stall = false.B
val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop))
instruction.io.in := io.instruction
instruction.io.stall := stall
instruction.io.flush := io.flush
io.output_instruction := instruction.io.out
val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress))
instruction_address.io.in := io.instruction_address
instruction_address.io.stall := stall
instruction_address.io.flush := io.flush
io.output_instruction_address := instruction_address.io.out
val regs_reg1_read_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits))
regs_reg1_read_address.io.in := io.regs_reg1_read_address
regs_reg1_read_address.io.stall := stall
regs_reg1_read_address.io.flush := io.flush
io.output_regs_reg1_read_address := regs_reg1_read_address.io.out
val regs_reg2_read_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits))
regs_reg2_read_address.io.in := io.regs_reg2_read_address
regs_reg2_read_address.io.stall := stall
regs_reg2_read_address.io.flush := io.flush
io.output_regs_reg2_read_address := regs_reg2_read_address.io.out
val regs_write_enable = Module(new PipelineRegister(1))
regs_write_enable.io.in := io.regs_write_enable
regs_write_enable.io.stall := stall
regs_write_enable.io.flush := io.flush
io.output_regs_write_enable := regs_write_enable.io.out
val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits))
regs_write_address.io.in := io.regs_write_address
regs_write_address.io.stall := stall
regs_write_address.io.flush := io.flush
io.output_regs_write_address := regs_write_address.io.out
val regs_write_source = Module(new PipelineRegister(2))
regs_write_source.io.in := io.regs_write_source
regs_write_source.io.stall := stall
regs_write_source.io.flush := io.flush
io.output_regs_write_source := regs_write_source.io.out
val reg1_data = Module(new PipelineRegister())
reg1_data.io.in := io.reg1_data
reg1_data.io.stall := stall
reg1_data.io.flush := io.flush
io.output_reg1_data := reg1_data.io.out
val reg2_data = Module(new PipelineRegister())
reg2_data.io.in := io.reg2_data
reg2_data.io.stall := stall
reg2_data.io.flush := io.flush
io.output_reg2_data := reg2_data.io.out
val immediate = Module(new PipelineRegister())
immediate.io.in := io.immediate
immediate.io.stall := stall
immediate.io.flush := io.flush
io.output_immediate := immediate.io.out
val aluop1_source = Module(new PipelineRegister(1))
aluop1_source.io.in := io.aluop1_source
aluop1_source.io.stall := stall
aluop1_source.io.flush := io.flush
io.output_aluop1_source := aluop1_source.io.out
val aluop2_source = Module(new PipelineRegister(1))
aluop2_source.io.in := io.aluop2_source
aluop2_source.io.stall := stall
aluop2_source.io.flush := io.flush
io.output_aluop2_source := aluop2_source.io.out
val csr_write_enable = Module(new PipelineRegister(1))
csr_write_enable.io.in := io.csr_write_enable
csr_write_enable.io.stall := stall
csr_write_enable.io.flush := io.flush
io.output_csr_write_enable := csr_write_enable.io.out
val csr_address = Module(new PipelineRegister(Parameters.CSRRegisterAddrBits))
csr_address.io.in := io.csr_address
csr_address.io.stall := stall
csr_address.io.flush := io.flush
io.output_csr_address := csr_address.io.out
val memory_read_enable = Module(new PipelineRegister(1))
memory_read_enable.io.in := io.memory_read_enable
memory_read_enable.io.stall := stall
memory_read_enable.io.flush := io.flush
io.output_memory_read_enable := memory_read_enable.io.out
val memory_write_enable = Module(new PipelineRegister(1))
memory_write_enable.io.in := io.memory_write_enable
memory_write_enable.io.stall := stall
memory_write_enable.io.flush := io.flush
io.output_memory_write_enable := memory_write_enable.io.out
val csr_read_data = Module(new PipelineRegister())
csr_read_data.io.in := io.csr_read_data
csr_read_data.io.stall := stall
csr_read_data.io.flush := io.flush
io.output_csr_read_data := csr_read_data.io.out
}

View File

@@ -0,0 +1,51 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_final
import chisel3._
import riscv.Parameters
import riscv.core.PipelineRegister
class IF2ID extends Module {
val io = IO(new Bundle {
val stall = Input(Bool())
val flush = Input(Bool())
val instruction = Input(UInt(Parameters.InstructionWidth))
val instruction_address = Input(UInt(Parameters.AddrWidth))
val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth))
val output_instruction = Output(UInt(Parameters.DataWidth))
val output_instruction_address = Output(UInt(Parameters.AddrWidth))
val output_interrupt_flag = Output(UInt(Parameters.InterruptFlagWidth))
})
val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop))
instruction.io.in := io.instruction
instruction.io.stall := io.stall
instruction.io.flush := io.flush
io.output_instruction := instruction.io.out
val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress))
instruction_address.io.in := io.instruction_address
instruction_address.io.stall := io.stall
instruction_address.io.flush := io.flush
io.output_instruction_address := instruction_address.io.out
val interrupt_flag = Module(new PipelineRegister(Parameters.InterruptFlagBits))
interrupt_flag.io.in := io.interrupt_flag
interrupt_flag.io.stall := io.stall
interrupt_flag.io.flush := io.flush
io.output_interrupt_flag := interrupt_flag.io.out
}

View File

@@ -0,0 +1,274 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_final
import chisel3._
import chisel3.util._
import riscv.Parameters
object InstructionTypes {
val L = "b0000011".U
val I = "b0010011".U
val S = "b0100011".U
val RM = "b0110011".U
val B = "b1100011".U
}
object Instructions {
val lui = "b0110111".U
val nop = "b0000001".U
val jal = "b1101111".U
val jalr = "b1100111".U
val auipc = "b0010111".U
val csr = "b1110011".U
val fence = "b0001111".U
}
object InstructionsTypeL {
val lb = "b000".U
val lh = "b001".U
val lw = "b010".U
val lbu = "b100".U
val lhu = "b101".U
}
object InstructionsTypeI {
val addi = 0.U
val slli = 1.U
val slti = 2.U
val sltiu = 3.U
val xori = 4.U
val sri = 5.U
val ori = 6.U
val andi = 7.U
}
object InstructionsTypeS {
val sb = "b000".U
val sh = "b001".U
val sw = "b010".U
}
object InstructionsTypeR {
val add_sub = 0.U
val sll = 1.U
val slt = 2.U
val sltu = 3.U
val xor = 4.U
val sr = 5.U
val or = 6.U
val and = 7.U
}
object InstructionsTypeM {
val mul = 0.U
val mulh = 1.U
val mulhsu = 2.U
val mulhum = 3.U
val div = 4.U
val divu = 5.U
val rem = 6.U
val remu = 7.U
}
object InstructionsTypeB {
val beq = "b000".U
val bne = "b001".U
val blt = "b100".U
val bge = "b101".U
val bltu = "b110".U
val bgeu = "b111".U
}
object InstructionsTypeCSR {
val csrrw = "b001".U
val csrrs = "b010".U
val csrrc = "b011".U
val csrrwi = "b101".U
val csrrsi = "b110".U
val csrrci = "b111".U
}
object InstructionsNop {
val nop = 0x00000013L.U(Parameters.DataWidth)
}
object InstructionsRet {
val mret = 0x30200073L.U(Parameters.DataWidth)
val ret = 0x00008067L.U(Parameters.DataWidth)
}
object InstructionsEnv {
val ecall = 0x00000073L.U(Parameters.DataWidth)
val ebreak = 0x00100073L.U(Parameters.DataWidth)
}
object ALUOp1Source {
val Register = 0.U(1.W)
val InstructionAddress = 1.U(1.W)
}
object ALUOp2Source {
val Register = 0.U(1.W)
val Immediate = 1.U(1.W)
}
object RegWriteSource {
val ALUResult = 0.U(2.W)
val Memory = 1.U(2.W)
val CSR = 2.U(2.W)
val NextInstructionAddress = 3.U(2.W)
}
class InstructionDecode extends Module {
val io = IO(new Bundle {
val instruction = Input(UInt(Parameters.InstructionWidth))
val instruction_address = Input(UInt(Parameters.AddrWidth))
val reg1_data = Input(UInt(Parameters.DataWidth))
val reg2_data = Input(UInt(Parameters.DataWidth))
val forward_from_mem = Input(UInt(Parameters.DataWidth))
val forward_from_wb = Input(UInt(Parameters.DataWidth))
val reg1_forward = Input(UInt(2.W))
val reg2_forward = Input(UInt(2.W))
val interrupt_assert = Input(Bool())
val interrupt_handler_address = Input(UInt(Parameters.AddrWidth))
val regs_reg1_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
val regs_reg2_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
val ex_immediate = Output(UInt(Parameters.DataWidth))
val ex_aluop1_source = Output(UInt(1.W))
val ex_aluop2_source = Output(UInt(1.W))
val ex_memory_read_enable = Output(Bool())
val ex_memory_write_enable = Output(Bool())
val ex_reg_write_source = Output(UInt(2.W))
val ex_reg_write_enable = Output(Bool())
val ex_reg_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
val ex_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth))
val ex_csr_write_enable = Output(Bool())
val ctrl_jump_instruction = Output(Bool())
val clint_jump_flag = Output(Bool())
val clint_jump_address = Output(UInt(Parameters.AddrWidth))
val if_jump_flag = Output(Bool())
val if_jump_address = Output(UInt(Parameters.AddrWidth))
})
val opcode = io.instruction(6, 0)
val funct3 = io.instruction(14, 12)
val funct7 = io.instruction(31, 25)
val rd = io.instruction(11, 7)
val rs1 = io.instruction(19, 15)
val rs2 = io.instruction(24, 20)
// Lab3(Final) ID rs
val rs1_used = opcode =/= Instructions.lui && opcode =/= Instructions.auipc && opcode =/= Instructions.jal
val rs2_used = opcode === InstructionTypes.RM || opcode === InstructionTypes.S || opcode === InstructionTypes.B
io.regs_reg1_read_address := Mux(rs1_used, rs1, 0.U)
io.regs_reg2_read_address := Mux(rs2_used, rs2, 0.U)
// Lab3(Final) ID rs End
io.ex_immediate := MuxLookup(
opcode,
Cat(Fill(20, io.instruction(31)), io.instruction(31, 20)),
IndexedSeq(
InstructionTypes.I -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)),
InstructionTypes.L -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)),
Instructions.jalr -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)),
InstructionTypes.S -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 25), io.instruction(11, 7)),
InstructionTypes.B -> Cat(Fill(20, io.instruction(31)), io.instruction(7), io.instruction(30, 25), io.instruction(11, 8), 0.U(1.W)),
Instructions.lui -> Cat(io.instruction(31, 12), 0.U(12.W)),
Instructions.auipc -> Cat(io.instruction(31, 12), 0.U(12.W)),
Instructions.jal -> Cat(Fill(12, io.instruction(31)), io.instruction(19, 12), io.instruction(20), io.instruction(30, 21), 0.U(1.W))
)
)
io.ex_aluop1_source := Mux(
opcode === Instructions.auipc || opcode === InstructionTypes.B || opcode === Instructions.jal,
ALUOp1Source.InstructionAddress,
ALUOp1Source.Register
)
io.ex_aluop2_source := Mux(
opcode === InstructionTypes.RM,
ALUOp2Source.Register,
ALUOp2Source.Immediate
)
io.ex_memory_read_enable := opcode === InstructionTypes.L
io.ex_memory_write_enable := opcode === InstructionTypes.S
io.ex_reg_write_source := MuxLookup(
opcode,
RegWriteSource.ALUResult,
IndexedSeq(
InstructionTypes.L -> RegWriteSource.Memory,
Instructions.csr -> RegWriteSource.CSR,
Instructions.jal -> RegWriteSource.NextInstructionAddress,
Instructions.jalr -> RegWriteSource.NextInstructionAddress
)
)
// Lab3(Final) ID rd
val rd_used = opcode === InstructionTypes.RM || opcode === InstructionTypes.I || opcode === InstructionTypes.L ||
opcode === Instructions.lui || opcode === Instructions.auipc || opcode === Instructions.jal ||
opcode === Instructions.jalr || opcode === Instructions.csr
io.ex_reg_write_enable := rd_used
io.ex_reg_write_address := Mux(rd_used, rd, 0.U)
// Lab3(Final) ID rd End
io.ex_csr_address := io.instruction(31, 20)
io.ex_csr_write_enable := (opcode === Instructions.csr) && (
funct3 === InstructionsTypeCSR.csrrw || funct3 === InstructionsTypeCSR.csrrwi ||
funct3 === InstructionsTypeCSR.csrrs || funct3 === InstructionsTypeCSR.csrrsi ||
funct3 === InstructionsTypeCSR.csrrc || funct3 === InstructionsTypeCSR.csrrci
)
// Lab3(Final)
val reg1_data = MuxLookup(io.reg1_forward, io.reg1_data)(
Seq(
ForwardingType.ForwardFromMEM -> io.forward_from_mem,
ForwardingType.ForwardFromWB -> io.forward_from_wb
)
)
val reg2_data = MuxLookup(io.reg2_forward, io.reg2_data)(
Seq(
ForwardingType.ForwardFromMEM -> io.forward_from_mem,
ForwardingType.ForwardFromWB -> io.forward_from_wb
)
)
val is_jump_instruction = opcode === Instructions.jal || opcode === Instructions.jalr || opcode === InstructionTypes.B
io.ctrl_jump_instruction := is_jump_instruction
val jump_condition_met =
(opcode === Instructions.jal) ||
(opcode === Instructions.jalr) ||
(opcode === InstructionTypes.B) && MuxLookup(
funct3,
false.B,
IndexedSeq(
InstructionsTypeB.beq -> (reg1_data === reg2_data),
InstructionsTypeB.bne -> (reg1_data =/= reg2_data),
InstructionsTypeB.blt -> (reg1_data.asSInt < reg2_data.asSInt),
InstructionsTypeB.bge -> (reg1_data.asSInt >= reg2_data.asSInt),
InstructionsTypeB.bltu -> (reg1_data < reg2_data),
InstructionsTypeB.bgeu -> (reg1_data >= reg2_data)
)
)
val jump_address = Mux(
opcode === Instructions.jalr,
(reg1_data.asSInt + io.ex_immediate.asSInt).asUInt,
(io.instruction_address.asSInt + io.ex_immediate.asSInt).asUInt
) & (~1.U(Parameters.DataWidth)).asUInt // Ensure address is even
io.clint_jump_flag := jump_condition_met
io.clint_jump_address := jump_address
io.if_jump_flag := jump_condition_met || io.interrupt_assert
io.if_jump_address := Mux(
io.interrupt_assert,
io.interrupt_handler_address,
jump_address
)
// Lab3(Final) End
}

View File

@@ -0,0 +1,48 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_final
import chisel3._
import chisel3.util.MuxCase
import riscv.Parameters
object ProgramCounter {
val EntryAddress = Parameters.EntryAddress
}
class InstructionFetch extends Module {
val io = IO(new Bundle {
val stall_flag_ctrl = Input(Bool())
val jump_flag_id = Input(Bool())
val jump_address_id = Input(UInt(Parameters.AddrWidth))
val rom_instruction = Input(UInt(Parameters.DataWidth))
val instruction_valid = Input(Bool())
val instruction_address = Output(UInt(Parameters.AddrWidth))
val id_instruction = Output(UInt(Parameters.InstructionWidth))
})
val pc = RegInit(ProgramCounter.EntryAddress)
pc := MuxCase(
pc + 4.U,
IndexedSeq(
(io.jump_flag_id && !io.stall_flag_ctrl) -> io.jump_address_id,
(io.stall_flag_ctrl || !io.instruction_valid) -> pc
)
)
io.instruction_address := pc
io.id_instruction := Mux(io.instruction_valid, io.rom_instruction, InstructionsNop.nop)
}

View File

@@ -0,0 +1,83 @@
// Copyright 2022 Canbin Huang
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_final
import chisel3._
import riscv.Parameters
import riscv.core.PipelineRegister
class MEM2WB extends Module {
val io = IO(new Bundle() {
val instruction_address = Input(UInt(Parameters.AddrWidth))
val alu_result = Input(UInt(Parameters.DataWidth))
val regs_write_enable = Input(Bool())
val regs_write_source = Input(UInt(2.W))
val regs_write_address = Input(UInt(Parameters.AddrWidth))
val memory_read_data = Input(UInt(Parameters.DataWidth))
val csr_read_data = Input(UInt(Parameters.DataWidth))
val output_instruction_address = Output(UInt(Parameters.AddrWidth))
val output_alu_result = Output(UInt(Parameters.DataWidth))
val output_regs_write_enable = Output(Bool())
val output_regs_write_source = Output(UInt(2.W))
val output_regs_write_address = Output(UInt(Parameters.AddrWidth))
val output_memory_read_data = Output(UInt(Parameters.DataWidth))
val output_csr_read_data = Output(UInt(Parameters.DataWidth))
})
val stall = false.B
val flush = false.B
val alu_result = Module(new PipelineRegister())
alu_result.io.in := io.alu_result
alu_result.io.stall := stall
alu_result.io.flush := flush
io.output_alu_result := alu_result.io.out
val memory_read_data = Module(new PipelineRegister())
memory_read_data.io.in := io.memory_read_data
memory_read_data.io.stall := stall
memory_read_data.io.flush := flush
io.output_memory_read_data := memory_read_data.io.out
val regs_write_enable = Module(new PipelineRegister(1))
regs_write_enable.io.in := io.regs_write_enable
regs_write_enable.io.stall := stall
regs_write_enable.io.flush := flush
io.output_regs_write_enable := regs_write_enable.io.out
val regs_write_source = Module(new PipelineRegister(2))
regs_write_source.io.in := io.regs_write_source
regs_write_source.io.stall := stall
regs_write_source.io.flush := flush
io.output_regs_write_source := regs_write_source.io.out
val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits))
regs_write_address.io.in := io.regs_write_address
regs_write_address.io.stall := stall
regs_write_address.io.flush := flush
io.output_regs_write_address := regs_write_address.io.out
val instruction_address = Module(new PipelineRegister(Parameters.InstructionBits))
instruction_address.io.in := io.instruction_address
instruction_address.io.stall := stall
instruction_address.io.flush := flush
io.output_instruction_address := instruction_address.io.out
val csr_read_data = Module(new PipelineRegister())
csr_read_data.io.in := io.csr_read_data
csr_read_data.io.stall := stall
csr_read_data.io.flush := flush
io.output_csr_read_data := csr_read_data.io.out
}

View 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 riscv.core.fivestage_final
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 regs_write_source = Input(UInt(2.W))
val csr_read_data = Input(UInt(Parameters.DataWidth))
val wb_memory_read_data = Output(UInt(Parameters.DataWidth))
val forward_data = Output(UInt(Parameters.DataWidth))
val bundle = Flipped(new RAMBundle)
})
val mem_address_index = io.alu_result(log2Up(Parameters.WordSize) - 1, 0).asUInt
io.bundle.write_enable := io.memory_write_enable
io.bundle.write_data := 0.U
io.bundle.address := io.alu_result
io.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.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.bundle.write_data := io.reg2_data
io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B))
when(io.funct3 === InstructionsTypeS.sb) {
io.bundle.write_strobe(mem_address_index) := true.B
io.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.bundle.write_strobe(i) := true.B
}
io.bundle.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0)
}.otherwise {
for (i <- Parameters.WordSize / 2 until Parameters.WordSize) {
io.bundle.write_strobe(i) := true.B
}
io.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.bundle.write_strobe(i) := true.B
}
}
}
io.forward_data := Mux(io.regs_write_source === RegWriteSource.CSR, io.csr_read_data, io.alu_result)
}

View File

@@ -0,0 +1,40 @@
// Copyright 2022 Canbin Huang
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_final
import chisel3._
import chisel3.util._
import riscv.Parameters
class WriteBack extends Module {
val io = IO(new Bundle() {
val instruction_address = Input(UInt(Parameters.AddrWidth))
val alu_result = Input(UInt(Parameters.DataWidth))
val memory_read_data = Input(UInt(Parameters.DataWidth))
val regs_write_source = Input(UInt(2.W))
val csr_read_data = Input(UInt(Parameters.DataWidth))
val regs_write_data = Output(UInt(Parameters.DataWidth))
})
io.regs_write_data := MuxLookup(
io.regs_write_source,
io.alu_result,
IndexedSeq(
RegWriteSource.Memory -> io.memory_read_data,
RegWriteSource.CSR -> io.csr_read_data,
RegWriteSource.NextInstructionAddress -> (io.instruction_address + 4.U)
)
)
}

View File

@@ -0,0 +1,103 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_forward
import chisel3._
import chisel3.util.MuxLookup
import riscv.Parameters
object InterruptStatus {
val None = 0x0.U(8.W)
val Timer0 = 0x1.U(8.W)
val Ret = 0xFF.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 {
val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth))
val instruction_ex = Input(UInt(Parameters.InstructionWidth))
val instruction_address_if = Input(UInt(Parameters.AddrWidth))
val instruction_address_id = Input(UInt(Parameters.AddrWidth))
val jump_flag = Input(Bool())
val jump_address = Input(UInt(Parameters.AddrWidth))
val ex_interrupt_handler_address = Output(UInt(Parameters.AddrWidth))
val ex_interrupt_assert = Output(Bool())
val csr_bundle = new CSRDirectAccessBundle
})
val interrupt_enable = io.csr_bundle.mstatus(3)
val jumpping = RegNext(io.jump_flag || io.ex_interrupt_assert)
val instruction_address = Mux(
io.jump_flag,
io.jump_address,
Mux(jumpping, io.instruction_address_if, io.instruction_address_id)
)
val mstatus_disable_interrupt = io.csr_bundle.mstatus(31, 4) ## 0.U(1.W) ## io.csr_bundle.mstatus(2, 0)
val mstatus_recover_interrupt = io.csr_bundle.mstatus(31, 4) ## io.csr_bundle.mstatus(7) ## io.csr_bundle.mstatus(2, 0)
when(io.instruction_ex === InstructionsEnv.ecall || io.instruction_ex === InstructionsEnv.ebreak) {
io.csr_bundle.mstatus_write_data := mstatus_disable_interrupt
io.csr_bundle.mepc_write_data := instruction_address
io.csr_bundle.mcause_write_data := MuxLookup(
io.instruction_ex,
10.U,
IndexedSeq(
InstructionsEnv.ecall -> 11.U,
InstructionsEnv.ebreak -> 3.U,
)
)
io.csr_bundle.direct_write_enable := true.B
io.ex_interrupt_assert := true.B
io.ex_interrupt_handler_address := io.csr_bundle.mtvec
}.elsewhen(io.interrupt_flag =/= InterruptStatus.None && interrupt_enable) {
io.csr_bundle.mstatus_write_data := mstatus_disable_interrupt
io.csr_bundle.mepc_write_data := instruction_address
io.csr_bundle.mcause_write_data := Mux(io.interrupt_flag(0), 0x80000007L.U, 0x8000000BL.U)
io.csr_bundle.direct_write_enable := true.B
io.ex_interrupt_assert := true.B
io.ex_interrupt_handler_address := io.csr_bundle.mtvec
}.elsewhen(io.instruction_ex === InstructionsRet.mret) {
io.csr_bundle.mstatus_write_data := mstatus_recover_interrupt
io.csr_bundle.mepc_write_data := io.csr_bundle.mepc
io.csr_bundle.mcause_write_data := io.csr_bundle.mcause
io.csr_bundle.direct_write_enable := true.B
io.ex_interrupt_assert := true.B
io.ex_interrupt_handler_address := io.csr_bundle.mepc
}.otherwise {
io.csr_bundle.mstatus_write_data := io.csr_bundle.mstatus
io.csr_bundle.mepc_write_data := io.csr_bundle.mepc
io.csr_bundle.mcause_write_data := io.csr_bundle.mcause
io.csr_bundle.direct_write_enable := false.B
io.ex_interrupt_assert := false.B
io.ex_interrupt_handler_address := 0.U
}
}

View File

@@ -0,0 +1,158 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_forward
import chisel3._
import riscv.Parameters
import riscv.core.{CPUBundle, CSR, RegisterFile}
class CPU extends Module {
val io = IO(new CPUBundle)
val ctrl = Module(new Control)
val regs = Module(new RegisterFile)
val inst_fetch = Module(new InstructionFetch)
val if2id = Module(new IF2ID)
val id = Module(new InstructionDecode)
val id2ex = Module(new ID2EX)
val ex = Module(new Execute)
val ex2mem = Module(new EX2MEM)
val mem = Module(new MemoryAccess)
val mem2wb = Module(new MEM2WB)
val wb = Module(new WriteBack)
val forwarding = Module(new Forwarding)
val clint = Module(new CLINT)
val csr_regs = Module(new CSR)
ctrl.io.jump_flag := ex.io.if_jump_flag
ctrl.io.rs1_id := id.io.regs_reg1_read_address
ctrl.io.rs2_id := id.io.regs_reg2_read_address
ctrl.io.memory_read_enable_ex := id2ex.io.output_memory_read_enable
ctrl.io.rd_ex := id2ex.io.output_regs_write_address
regs.io.write_enable := mem2wb.io.output_regs_write_enable
regs.io.write_address := mem2wb.io.output_regs_write_address
regs.io.write_data := wb.io.regs_write_data
regs.io.read_address1 := id.io.regs_reg1_read_address
regs.io.read_address2 := id.io.regs_reg2_read_address
regs.io.debug_read_address := io.debug_read_address
io.debug_read_data := regs.io.debug_read_data
io.instruction_address := inst_fetch.io.instruction_address
inst_fetch.io.stall_flag_ctrl := ctrl.io.pc_stall
inst_fetch.io.jump_flag_id := ex.io.if_jump_flag
inst_fetch.io.jump_address_id := ex.io.if_jump_address
inst_fetch.io.rom_instruction := io.instruction
inst_fetch.io.instruction_valid := io.instruction_valid
if2id.io.stall := ctrl.io.if2id_stall
if2id.io.flush := ctrl.io.if2id_flush
if2id.io.instruction := inst_fetch.io.id_instruction
if2id.io.instruction_address := inst_fetch.io.instruction_address
if2id.io.interrupt_flag := io.interrupt_flag
id.io.instruction := if2id.io.output_instruction
id2ex.io.flush := ctrl.io.id2ex_flush
id2ex.io.instruction := if2id.io.output_instruction
id2ex.io.instruction_address := if2id.io.output_instruction_address
id2ex.io.reg1_data := regs.io.read_data1
id2ex.io.reg2_data := regs.io.read_data2
id2ex.io.regs_reg1_read_address := id.io.regs_reg1_read_address
id2ex.io.regs_reg2_read_address := id.io.regs_reg2_read_address
id2ex.io.regs_write_enable := id.io.ex_reg_write_enable
id2ex.io.regs_write_address := id.io.ex_reg_write_address
id2ex.io.regs_write_source := id.io.ex_reg_write_source
id2ex.io.immediate := id.io.ex_immediate
id2ex.io.aluop1_source := id.io.ex_aluop1_source
id2ex.io.aluop2_source := id.io.ex_aluop2_source
id2ex.io.csr_write_enable := id.io.ex_csr_write_enable
id2ex.io.csr_address := id.io.ex_csr_address
id2ex.io.memory_read_enable := id.io.ex_memory_read_enable
id2ex.io.memory_write_enable := id.io.ex_memory_write_enable
id2ex.io.csr_read_data := csr_regs.io.id_reg_read_data
ex.io.instruction := id2ex.io.output_instruction
ex.io.instruction_address := id2ex.io.output_instruction_address
ex.io.reg1_data := id2ex.io.output_reg1_data
ex.io.reg2_data := id2ex.io.output_reg2_data
ex.io.immediate_id := id2ex.io.output_immediate
ex.io.aluop1_source_id := id2ex.io.output_aluop1_source
ex.io.aluop2_source_id := id2ex.io.output_aluop2_source
ex.io.csr_read_data_id := id2ex.io.output_csr_read_data
ex.io.forward_from_mem := mem.io.forward_data
ex.io.forward_from_wb := wb.io.regs_write_data
ex.io.reg1_forward := forwarding.io.reg1_forward_ex
ex.io.reg2_forward := forwarding.io.reg2_forward_ex
ex.io.interrupt_assert_clint := clint.io.ex_interrupt_assert
ex.io.interrupt_handler_address_clint := clint.io.ex_interrupt_handler_address
ex2mem.io.regs_write_enable := id2ex.io.output_regs_write_enable
ex2mem.io.regs_write_source := id2ex.io.output_regs_write_source
ex2mem.io.regs_write_address := id2ex.io.output_regs_write_address
ex2mem.io.instruction_address := id2ex.io.output_instruction_address
ex2mem.io.funct3 := id2ex.io.output_instruction(14, 12)
ex2mem.io.reg2_data := ex.io.mem_reg2_data
ex2mem.io.memory_read_enable := id2ex.io.output_memory_read_enable
ex2mem.io.memory_write_enable := id2ex.io.output_memory_write_enable
ex2mem.io.alu_result := ex.io.mem_alu_result
ex2mem.io.csr_read_data := id2ex.io.output_csr_read_data
mem.io.alu_result := ex2mem.io.output_alu_result
mem.io.reg2_data := ex2mem.io.output_reg2_data
mem.io.memory_read_enable := ex2mem.io.output_memory_read_enable
mem.io.memory_write_enable := ex2mem.io.output_memory_write_enable
mem.io.funct3 := ex2mem.io.output_funct3
mem.io.regs_write_source := ex2mem.io.output_regs_write_source
mem.io.csr_read_data := ex2mem.io.output_csr_read_data
io.device_select := mem.io.bundle.address(Parameters.AddrBits - 1, Parameters.AddrBits - Parameters.SlaveDeviceCountBits)
io.memory_bundle <> mem.io.bundle
io.memory_bundle.address := 0.U(Parameters.SlaveDeviceCountBits.W) ## mem.io.bundle.address(Parameters.AddrBits - 1 - Parameters.SlaveDeviceCountBits, 0)
mem2wb.io.instruction_address := ex2mem.io.output_instruction_address
mem2wb.io.alu_result := ex2mem.io.output_alu_result
mem2wb.io.regs_write_enable := ex2mem.io.output_regs_write_enable
mem2wb.io.regs_write_source := ex2mem.io.output_regs_write_source
mem2wb.io.regs_write_address := ex2mem.io.output_regs_write_address
mem2wb.io.memory_read_data := mem.io.wb_memory_read_data
mem2wb.io.csr_read_data := ex2mem.io.output_csr_read_data
wb.io.instruction_address := mem2wb.io.output_instruction_address
wb.io.alu_result := mem2wb.io.output_alu_result
wb.io.memory_read_data := mem2wb.io.output_memory_read_data
wb.io.regs_write_source := mem2wb.io.output_regs_write_source
wb.io.csr_read_data := mem2wb.io.output_csr_read_data
forwarding.io.rs1_ex := id2ex.io.output_regs_reg1_read_address
forwarding.io.rs2_ex := id2ex.io.output_regs_reg2_read_address
forwarding.io.rd_mem := ex2mem.io.output_regs_write_address
forwarding.io.reg_write_enable_mem := ex2mem.io.output_regs_write_enable
forwarding.io.rd_wb := mem2wb.io.output_regs_write_address
forwarding.io.reg_write_enable_wb := mem2wb.io.output_regs_write_enable
clint.io.instruction_address_if := inst_fetch.io.instruction_address
clint.io.instruction_address_id := if2id.io.output_instruction_address
clint.io.instruction_ex := id2ex.io.output_instruction
clint.io.jump_flag := ex.io.clint_jump_flag
clint.io.jump_address := ex.io.clint_jump_address
clint.io.interrupt_flag := if2id.io.output_interrupt_flag
clint.io.csr_bundle <> csr_regs.io.clint_access_bundle
csr_regs.io.reg_read_address_id := id.io.ex_csr_address
csr_regs.io.reg_write_enable_ex := id2ex.io.output_csr_write_enable
csr_regs.io.reg_write_address_ex := id2ex.io.output_csr_address
csr_regs.io.reg_write_data_ex := ex.io.csr_write_data
}

View File

@@ -0,0 +1,44 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_forward
import chisel3._
import riscv.Parameters
class Control extends Module {
val io = IO(new Bundle {
val jump_flag = Input(Bool())
val rs1_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val rs2_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val memory_read_enable_ex = Input(Bool())
val rd_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val if2id_flush = Output(Bool())
val id2ex_flush = Output(Bool())
val pc_stall = Output(Bool())
val if2id_stall = Output(Bool())
})
// Lab3(Forward)
val load_use_hazard = io.memory_read_enable_ex &&
(io.rd_ex === io.rs1_id || io.rd_ex === io.rs2_id) &&
io.rd_ex =/= 0.U
val flush = io.jump_flag
io.pc_stall := load_use_hazard && !flush
io.if2id_stall := load_use_hazard && !flush
io.if2id_flush := flush
io.id2ex_flush := flush || load_use_hazard
// Lab3(Forward) End
}

View File

@@ -0,0 +1,108 @@
// Copyright 2022 Canbin Huang
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_forward
import chisel3._
import riscv.Parameters
import riscv.core.PipelineRegister
class EX2MEM extends Module {
val io = IO(new Bundle() {
val regs_write_enable = Input(Bool())
val regs_write_source = Input(UInt(2.W))
val regs_write_address = Input(UInt(Parameters.AddrWidth))
val instruction_address = Input(UInt(Parameters.AddrWidth))
val funct3 = Input(UInt(3.W))
val reg2_data = Input(UInt(Parameters.DataWidth))
val memory_read_enable = Input(Bool())
val memory_write_enable = Input(Bool())
val alu_result = Input(UInt(Parameters.DataWidth))
val csr_read_data = Input(UInt(Parameters.DataWidth))
val output_regs_write_enable = Output(Bool())
val output_regs_write_source = Output(UInt(2.W))
val output_regs_write_address = Output(UInt(Parameters.AddrWidth))
val output_instruction_address = Output(UInt(Parameters.AddrWidth))
val output_funct3 = Output(UInt(Parameters.DataWidth))
val output_reg2_data = Output(UInt(Parameters.DataWidth))
val output_memory_read_enable = Output(Bool())
val output_memory_write_enable = Output(Bool())
val output_alu_result = Output(UInt(Parameters.DataWidth))
val output_csr_read_data = Output(UInt(Parameters.DataWidth))
})
val stall = false.B
val flush = false.B
val regs_write_enable = Module(new PipelineRegister(1))
regs_write_enable.io.in := io.regs_write_enable
regs_write_enable.io.stall := stall
regs_write_enable.io.flush := flush
io.output_regs_write_enable := regs_write_enable.io.out
val regs_write_source = Module(new PipelineRegister(2))
regs_write_source.io.in := io.regs_write_source
regs_write_source.io.stall := stall
regs_write_source.io.flush := flush
io.output_regs_write_source := regs_write_source.io.out
val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits))
regs_write_address.io.in := io.regs_write_address
regs_write_address.io.stall := stall
regs_write_address.io.flush := flush
io.output_regs_write_address := regs_write_address.io.out
val instruction_address = Module(new PipelineRegister(Parameters.AddrBits))
instruction_address.io.in := io.instruction_address
instruction_address.io.stall := stall
instruction_address.io.flush := flush
io.output_instruction_address := instruction_address.io.out
val funct3 = Module(new PipelineRegister(3))
funct3.io.in := io.funct3
funct3.io.stall := stall
funct3.io.flush := flush
io.output_funct3 := funct3.io.out
val reg2_data = Module(new PipelineRegister())
reg2_data.io.in := io.reg2_data
reg2_data.io.stall := stall
reg2_data.io.flush := flush
io.output_reg2_data := reg2_data.io.out
val alu_result = Module(new PipelineRegister())
alu_result.io.in := io.alu_result
alu_result.io.stall := stall
alu_result.io.flush := flush
io.output_alu_result := alu_result.io.out
val memory_read_enable = Module(new PipelineRegister(1))
memory_read_enable.io.in := io.memory_read_enable
memory_read_enable.io.stall := stall
memory_read_enable.io.flush := flush
io.output_memory_read_enable := memory_read_enable.io.out
val memory_write_enable = Module(new PipelineRegister(1))
memory_write_enable.io.in := io.memory_write_enable
memory_write_enable.io.stall := stall
memory_write_enable.io.flush := flush
io.output_memory_write_enable := memory_write_enable.io.out
val csr_read_data = Module(new PipelineRegister())
csr_read_data.io.in := io.csr_read_data
csr_read_data.io.stall := stall
csr_read_data.io.flush := flush
io.output_csr_read_data := csr_read_data.io.out
}

View File

@@ -0,0 +1,121 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_forward
import chisel3._
import chisel3.util._
import riscv.Parameters
import riscv.core.{ALU, ALUControl}
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_id = Input(UInt(Parameters.DataWidth))
val aluop1_source_id = Input(UInt(1.W))
val aluop2_source_id = Input(UInt(1.W))
val csr_read_data_id = Input(UInt(Parameters.DataWidth))
val forward_from_mem = Input(UInt(Parameters.DataWidth))
val forward_from_wb = Input(UInt(Parameters.DataWidth))
val reg1_forward = Input(UInt(2.W))
val reg2_forward = Input(UInt(2.W))
val interrupt_assert_clint = Input(Bool())
val interrupt_handler_address_clint = Input(UInt(Parameters.AddrWidth))
val mem_alu_result = Output(UInt(Parameters.DataWidth))
val mem_reg2_data = Output(UInt(Parameters.DataWidth))
val csr_write_data = Output(UInt(Parameters.DataWidth))
val if_jump_flag = Output(Bool())
val if_jump_address = Output(UInt(Parameters.AddrWidth))
val clint_jump_flag = Output(Bool())
val clint_jump_address = Output(UInt(Parameters.AddrWidth))
})
val opcode = io.instruction(6, 0)
val funct3 = io.instruction(14, 12)
val funct7 = io.instruction(31, 25)
val uimm = io.instruction(19, 15)
// ALU compute
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
// Lab3(Forward)
val reg1_data = MuxLookup(io.reg1_forward, io.reg1_data)(
Seq(
ForwardingType.ForwardFromMEM -> io.forward_from_mem,
ForwardingType.ForwardFromWB -> io.forward_from_wb
)
)
val reg2_data = MuxLookup(io.reg2_forward, io.reg2_data)(
Seq(
ForwardingType.ForwardFromMEM -> io.forward_from_mem,
ForwardingType.ForwardFromWB -> io.forward_from_wb
)
)
// Lab3(Forward) End
alu.io.op1 := Mux(
io.aluop1_source_id === ALUOp1Source.InstructionAddress,
io.instruction_address,
reg1_data
)
alu.io.op2 := Mux(
io.aluop2_source_id === ALUOp2Source.Immediate,
io.immediate_id,
reg2_data
)
io.mem_alu_result := alu.io.result
io.mem_reg2_data := reg2_data
io.csr_write_data := MuxLookup(funct3, 0.U, IndexedSeq(
InstructionsTypeCSR.csrrw -> reg1_data,
InstructionsTypeCSR.csrrc -> io.csr_read_data_id.&((~reg1_data).asUInt),
InstructionsTypeCSR.csrrs -> io.csr_read_data_id.|(reg1_data),
InstructionsTypeCSR.csrrwi -> Cat(0.U(27.W), uimm),
InstructionsTypeCSR.csrrci -> io.csr_read_data_id.&((~Cat(0.U(27.W), uimm)).asUInt),
InstructionsTypeCSR.csrrsi -> io.csr_read_data_id.|(Cat(0.U(27.W), uimm)),
))
// jump and interrupt
val instruction_jump_flag = (opcode === Instructions.jal) ||
(opcode === Instructions.jalr) ||
(opcode === InstructionTypes.B) && MuxLookup(
funct3,
false.B,
IndexedSeq(
InstructionsTypeB.beq -> (reg1_data === reg2_data),
InstructionsTypeB.bne -> (reg1_data =/= reg2_data),
InstructionsTypeB.blt -> (reg1_data.asSInt < reg2_data.asSInt),
InstructionsTypeB.bge -> (reg1_data.asSInt >= reg2_data.asSInt),
InstructionsTypeB.bltu -> (reg1_data.asUInt < reg2_data.asUInt),
InstructionsTypeB.bgeu -> (reg1_data.asUInt >= reg2_data.asUInt)
)
)
io.clint_jump_flag := instruction_jump_flag
io.clint_jump_address := alu.io.result
io.if_jump_flag := io.interrupt_assert_clint || instruction_jump_flag
io.if_jump_address := Mux(io.interrupt_assert_clint,
io.interrupt_handler_address_clint,
alu.io.result
)
}

View File

@@ -0,0 +1,56 @@
// Copyright 2022 Canbin Huang
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_forward
import chisel3._
import riscv.Parameters
object ForwardingType {
val NoForward = 0.U(2.W)
val ForwardFromMEM = 1.U(2.W)
val ForwardFromWB = 2.U(2.W)
}
class Forwarding extends Module {
val io = IO(new Bundle() {
val rs1_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val rs2_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val rd_mem = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val reg_write_enable_mem = Input(Bool())
val rd_wb = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val reg_write_enable_wb = Input(Bool())
// Forwarding Type
val reg1_forward_ex = Output(UInt(2.W))
val reg2_forward_ex = Output(UInt(2.W))
})
// Lab3(Forward)
// io.reg1_forward_ex := 0.U
// io.reg2_forward_ex := 0.U
io.reg1_forward_ex := ForwardingType.NoForward
io.reg2_forward_ex := ForwardingType.NoForward
when(io.reg_write_enable_mem && io.rd_mem =/= 0.U && io.rd_mem === io.rs1_ex) {
io.reg1_forward_ex := ForwardingType.ForwardFromMEM
}.elsewhen(io.reg_write_enable_wb && io.rd_wb =/= 0.U && io.rd_wb === io.rs1_ex) {
io.reg1_forward_ex := ForwardingType.ForwardFromWB
}
when(io.reg_write_enable_mem && io.rd_mem =/= 0.U && io.rd_mem === io.rs2_ex) {
io.reg2_forward_ex := ForwardingType.ForwardFromMEM
}.elsewhen(io.reg_write_enable_wb && io.rd_wb =/= 0.U && io.rd_wb === io.rs2_ex) {
io.reg2_forward_ex := ForwardingType.ForwardFromWB
}
// Lab3(Forward) End
}

View File

@@ -0,0 +1,164 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_forward
import chisel3._
import riscv.Parameters
import riscv.core.PipelineRegister
class ID2EX extends Module {
val io = IO(new Bundle {
val flush = Input(Bool())
val instruction = Input(UInt(Parameters.InstructionWidth))
val instruction_address = Input(UInt(Parameters.AddrWidth))
val regs_reg1_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val regs_reg2_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val regs_write_enable = Input(Bool())
val regs_write_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val regs_write_source = Input(UInt(2.W))
val reg1_data = Input(UInt(Parameters.DataWidth))
val reg2_data = Input(UInt(Parameters.DataWidth))
val immediate = Input(UInt(Parameters.DataWidth))
val aluop1_source = Input(UInt(1.W))
val aluop2_source = Input(UInt(1.W))
val csr_write_enable = Input(Bool())
val csr_address = Input(UInt(Parameters.CSRRegisterAddrWidth))
val memory_read_enable = Input(Bool())
val memory_write_enable = Input(Bool())
val csr_read_data = Input(UInt(Parameters.DataWidth))
val output_instruction = Output(UInt(Parameters.DataWidth))
val output_instruction_address = Output(UInt(Parameters.AddrWidth))
val output_regs_reg1_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
val output_regs_reg2_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
val output_regs_write_enable = Output(Bool())
val output_regs_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
val output_regs_write_source = Output(UInt(2.W))
val output_reg1_data = Output(UInt(Parameters.DataWidth))
val output_reg2_data = Output(UInt(Parameters.DataWidth))
val output_immediate = Output(UInt(Parameters.DataWidth))
val output_aluop1_source = Output(UInt(1.W))
val output_aluop2_source = Output(UInt(1.W))
val output_csr_write_enable = Output(Bool())
val output_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth))
val output_memory_read_enable = Output(Bool())
val output_memory_write_enable = Output(Bool())
val output_csr_read_data = Output(UInt(Parameters.DataWidth))
})
val stall = false.B
val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop))
instruction.io.in := io.instruction
instruction.io.stall := stall
instruction.io.flush := io.flush
io.output_instruction := instruction.io.out
val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress))
instruction_address.io.in := io.instruction_address
instruction_address.io.stall := stall
instruction_address.io.flush := io.flush
io.output_instruction_address := instruction_address.io.out
val regs_reg1_read_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits))
regs_reg1_read_address.io.in := io.regs_reg1_read_address
regs_reg1_read_address.io.stall := stall
regs_reg1_read_address.io.flush := io.flush
io.output_regs_reg1_read_address := regs_reg1_read_address.io.out
val regs_reg2_read_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits))
regs_reg2_read_address.io.in := io.regs_reg2_read_address
regs_reg2_read_address.io.stall := stall
regs_reg2_read_address.io.flush := io.flush
io.output_regs_reg2_read_address := regs_reg2_read_address.io.out
val regs_write_enable = Module(new PipelineRegister(1))
regs_write_enable.io.in := io.regs_write_enable
regs_write_enable.io.stall := stall
regs_write_enable.io.flush := io.flush
io.output_regs_write_enable := regs_write_enable.io.out
val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits))
regs_write_address.io.in := io.regs_write_address
regs_write_address.io.stall := stall
regs_write_address.io.flush := io.flush
io.output_regs_write_address := regs_write_address.io.out
val regs_write_source = Module(new PipelineRegister(2))
regs_write_source.io.in := io.regs_write_source
regs_write_source.io.stall := stall
regs_write_source.io.flush := io.flush
io.output_regs_write_source := regs_write_source.io.out
val reg1_data = Module(new PipelineRegister())
reg1_data.io.in := io.reg1_data
reg1_data.io.stall := stall
reg1_data.io.flush := io.flush
io.output_reg1_data := reg1_data.io.out
val reg2_data = Module(new PipelineRegister())
reg2_data.io.in := io.reg2_data
reg2_data.io.stall := stall
reg2_data.io.flush := io.flush
io.output_reg2_data := reg2_data.io.out
val immediate = Module(new PipelineRegister())
immediate.io.in := io.immediate
immediate.io.stall := stall
immediate.io.flush := io.flush
io.output_immediate := immediate.io.out
val aluop1_source = Module(new PipelineRegister(1))
aluop1_source.io.in := io.aluop1_source
aluop1_source.io.stall := stall
aluop1_source.io.flush := io.flush
io.output_aluop1_source := aluop1_source.io.out
val aluop2_source = Module(new PipelineRegister(1))
aluop2_source.io.in := io.aluop2_source
aluop2_source.io.stall := stall
aluop2_source.io.flush := io.flush
io.output_aluop2_source := aluop2_source.io.out
val csr_write_enable = Module(new PipelineRegister(1))
csr_write_enable.io.in := io.csr_write_enable
csr_write_enable.io.stall := stall
csr_write_enable.io.flush := io.flush
io.output_csr_write_enable := csr_write_enable.io.out
val csr_address = Module(new PipelineRegister(Parameters.CSRRegisterAddrBits))
csr_address.io.in := io.csr_address
csr_address.io.stall := stall
csr_address.io.flush := io.flush
io.output_csr_address := csr_address.io.out
val memory_read_enable = Module(new PipelineRegister(1))
memory_read_enable.io.in := io.memory_read_enable
memory_read_enable.io.stall := stall
memory_read_enable.io.flush := io.flush
io.output_memory_read_enable := memory_read_enable.io.out
val memory_write_enable = Module(new PipelineRegister(1))
memory_write_enable.io.in := io.memory_write_enable
memory_write_enable.io.stall := stall
memory_write_enable.io.flush := io.flush
io.output_memory_write_enable := memory_write_enable.io.out
val csr_read_data = Module(new PipelineRegister())
csr_read_data.io.in := io.csr_read_data
csr_read_data.io.stall := stall
csr_read_data.io.flush := io.flush
io.output_csr_read_data := csr_read_data.io.out
}

View File

@@ -0,0 +1,51 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_forward
import chisel3._
import riscv.Parameters
import riscv.core.PipelineRegister
class IF2ID extends Module {
val io = IO(new Bundle {
val stall = Input(Bool())
val flush = Input(Bool())
val instruction = Input(UInt(Parameters.InstructionWidth))
val instruction_address = Input(UInt(Parameters.AddrWidth))
val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth))
val output_instruction = Output(UInt(Parameters.DataWidth))
val output_instruction_address = Output(UInt(Parameters.AddrWidth))
val output_interrupt_flag = Output(UInt(Parameters.InterruptFlagWidth))
})
val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop))
instruction.io.in := io.instruction
instruction.io.stall := io.stall
instruction.io.flush := io.flush
io.output_instruction := instruction.io.out
val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress))
instruction_address.io.in := io.instruction_address
instruction_address.io.stall := io.stall
instruction_address.io.flush := io.flush
io.output_instruction_address := instruction_address.io.out
val interrupt_flag = Module(new PipelineRegister(Parameters.InterruptFlagBits))
interrupt_flag.io.in := io.interrupt_flag
interrupt_flag.io.stall := io.stall
interrupt_flag.io.flush := io.flush
io.output_interrupt_flag := interrupt_flag.io.out
}

View File

@@ -0,0 +1,218 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_forward
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(Bool())
val ex_aluop2_source = Output(Bool())
val ex_memory_read_enable = Output(Bool())
val ex_memory_write_enable = Output(Bool())
val ex_reg_write_source = Output(UInt(2.W))
val ex_reg_write_enable = Output(Bool())
val ex_reg_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
val ex_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth))
val ex_csr_write_enable = Output(Bool())
})
val 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)
// Lab3(Forward) ID rs
// io.regs_reg1_read_address := rs1
// io.regs_reg2_read_address := rs2
val rs1_used = opcode =/= Instructions.lui && opcode =/= Instructions.auipc && opcode =/= Instructions.jal
val rs2_used = opcode === InstructionTypes.RM || opcode === InstructionTypes.S || opcode === InstructionTypes.B
io.regs_reg1_read_address := Mux(rs1_used, rs1, 0.U)
io.regs_reg2_read_address := Mux(rs2_used, rs2, 0.U)
// Lab3(Forward) ID rs End
io.ex_immediate := MuxLookup(
opcode,
Cat(Fill(20, io.instruction(31)), io.instruction(31, 20)),
IndexedSeq(
InstructionTypes.I -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)),
InstructionTypes.L -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)),
Instructions.jalr -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)),
InstructionTypes.S -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 25), io.instruction(11, 7)),
InstructionTypes.B -> Cat(Fill(20, io.instruction(31)), io.instruction(7), io.instruction(30, 25), io.instruction(11, 8), 0.U(1.W)),
Instructions.lui -> Cat(io.instruction(31, 12), 0.U(12.W)),
Instructions.auipc -> Cat(io.instruction(31, 12), 0.U(12.W)),
Instructions.jal -> Cat(Fill(12, io.instruction(31)), io.instruction(19, 12), io.instruction(20), io.instruction(30, 21), 0.U(1.W))
)
)
io.ex_aluop1_source := Mux(
opcode === Instructions.auipc || opcode === InstructionTypes.B || opcode === Instructions.jal,
ALUOp1Source.InstructionAddress,
ALUOp1Source.Register
)
io.ex_aluop2_source := Mux(
opcode === InstructionTypes.RM,
ALUOp2Source.Register,
ALUOp2Source.Immediate
)
io.ex_memory_read_enable := opcode === InstructionTypes.L
io.ex_memory_write_enable := opcode === InstructionTypes.S
io.ex_reg_write_source := MuxLookup(
opcode,
RegWriteSource.ALUResult,
IndexedSeq(
InstructionTypes.L -> RegWriteSource.Memory,
Instructions.csr -> RegWriteSource.CSR,
Instructions.jal -> RegWriteSource.NextInstructionAddress,
Instructions.jalr -> RegWriteSource.NextInstructionAddress
)
)
// Lab3(Forward) ID rd
// io.ex_reg_write_enable := false.B
// io.ex_reg_write_address := rd
val rd_used = opcode === InstructionTypes.RM || opcode === InstructionTypes.I || opcode === InstructionTypes.L ||
opcode === Instructions.lui || opcode === Instructions.auipc || opcode === Instructions.jal ||
opcode === Instructions.jalr || opcode === Instructions.csr
io.ex_reg_write_enable := rd_used
io.ex_reg_write_address := Mux(rd_used, rd, 0.U)
// Lab3(Forward) ID rd End
io.ex_csr_address := io.instruction(31, 20)
io.ex_csr_write_enable := (opcode === Instructions.csr) && (
funct3 === InstructionsTypeCSR.csrrw || funct3 === InstructionsTypeCSR.csrrwi ||
funct3 === InstructionsTypeCSR.csrrs || funct3 === InstructionsTypeCSR.csrrsi ||
funct3 === InstructionsTypeCSR.csrrc || funct3 === InstructionsTypeCSR.csrrci
)
}

View File

@@ -0,0 +1,48 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_forward
import chisel3._
import chisel3.util.MuxCase
import riscv.Parameters
object ProgramCounter {
val EntryAddress = Parameters.EntryAddress
}
class InstructionFetch extends Module {
val io = IO(new Bundle {
val stall_flag_ctrl = Input(Bool())
val jump_flag_id = Input(Bool())
val jump_address_id = Input(UInt(Parameters.AddrWidth))
val rom_instruction = Input(UInt(Parameters.DataWidth))
val instruction_valid = Input(Bool())
val instruction_address = Output(UInt(Parameters.AddrWidth))
val id_instruction = Output(UInt(Parameters.InstructionWidth))
})
val pc = RegInit(ProgramCounter.EntryAddress)
pc := MuxCase(
pc + 4.U,
IndexedSeq(
(io.jump_flag_id && !io.stall_flag_ctrl) -> io.jump_address_id,
(io.stall_flag_ctrl || !io.instruction_valid) -> pc
)
)
io.instruction_address := pc
io.id_instruction := Mux(io.instruction_valid, io.rom_instruction, InstructionsNop.nop)
}

View File

@@ -0,0 +1,83 @@
// Copyright 2022 Canbin Huang
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_forward
import chisel3._
import riscv.Parameters
import riscv.core.PipelineRegister
class MEM2WB extends Module {
val io = IO(new Bundle() {
val instruction_address = Input(UInt(Parameters.AddrWidth))
val alu_result = Input(UInt(Parameters.DataWidth))
val regs_write_enable = Input(Bool())
val regs_write_source = Input(UInt(2.W))
val regs_write_address = Input(UInt(Parameters.AddrWidth))
val memory_read_data = Input(UInt(Parameters.DataWidth))
val csr_read_data = Input(UInt(Parameters.DataWidth))
val output_instruction_address = Output(UInt(Parameters.AddrWidth))
val output_alu_result = Output(UInt(Parameters.DataWidth))
val output_regs_write_enable = Output(Bool())
val output_regs_write_source = Output(UInt(2.W))
val output_regs_write_address = Output(UInt(Parameters.AddrWidth))
val output_memory_read_data = Output(UInt(Parameters.DataWidth))
val output_csr_read_data = Output(UInt(Parameters.DataWidth))
})
val stall = false.B
val flush = false.B
val alu_result = Module(new PipelineRegister())
alu_result.io.in := io.alu_result
alu_result.io.stall := stall
alu_result.io.flush := flush
io.output_alu_result := alu_result.io.out
val memory_read_data = Module(new PipelineRegister())
memory_read_data.io.in := io.memory_read_data
memory_read_data.io.stall := stall
memory_read_data.io.flush := flush
io.output_memory_read_data := memory_read_data.io.out
val regs_write_enable = Module(new PipelineRegister(1))
regs_write_enable.io.in := io.regs_write_enable
regs_write_enable.io.stall := stall
regs_write_enable.io.flush := flush
io.output_regs_write_enable := regs_write_enable.io.out
val regs_write_source = Module(new PipelineRegister(2))
regs_write_source.io.in := io.regs_write_source
regs_write_source.io.stall := stall
regs_write_source.io.flush := flush
io.output_regs_write_source := regs_write_source.io.out
val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits))
regs_write_address.io.in := io.regs_write_address
regs_write_address.io.stall := stall
regs_write_address.io.flush := flush
io.output_regs_write_address := regs_write_address.io.out
val instruction_address = Module(new PipelineRegister(Parameters.InstructionBits))
instruction_address.io.in := io.instruction_address
instruction_address.io.stall := stall
instruction_address.io.flush := flush
io.output_instruction_address := instruction_address.io.out
val csr_read_data = Module(new PipelineRegister())
csr_read_data.io.in := io.csr_read_data
csr_read_data.io.stall := stall
csr_read_data.io.flush := flush
io.output_csr_read_data := csr_read_data.io.out
}

View 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 riscv.core.fivestage_forward
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 regs_write_source = Input(UInt(2.W))
val csr_read_data = Input(UInt(Parameters.DataWidth))
val wb_memory_read_data = Output(UInt(Parameters.DataWidth))
val forward_data = Output(UInt(Parameters.DataWidth))
val bundle = Flipped(new RAMBundle)
})
val mem_address_index = io.alu_result(log2Up(Parameters.WordSize) - 1, 0).asUInt
io.bundle.write_enable := io.memory_write_enable
io.bundle.write_data := 0.U
io.bundle.address := io.alu_result
io.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.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.bundle.write_data := io.reg2_data
io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B))
when(io.funct3 === InstructionsTypeS.sb) {
io.bundle.write_strobe(mem_address_index) := true.B
io.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.bundle.write_strobe(i) := true.B
}
io.bundle.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0)
}.otherwise {
for (i <- Parameters.WordSize / 2 until Parameters.WordSize) {
io.bundle.write_strobe(i) := true.B
}
io.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.bundle.write_strobe(i) := true.B
}
}
}
io.forward_data := Mux(io.regs_write_source === RegWriteSource.CSR, io.csr_read_data, io.alu_result)
}

View File

@@ -0,0 +1,40 @@
// Copyright 2022 Canbin Huang
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_forward
import chisel3._
import chisel3.util._
import riscv.Parameters
class WriteBack extends Module {
val io = IO(new Bundle() {
val instruction_address = Input(UInt(Parameters.AddrWidth))
val alu_result = Input(UInt(Parameters.DataWidth))
val memory_read_data = Input(UInt(Parameters.DataWidth))
val regs_write_source = Input(UInt(2.W))
val csr_read_data = Input(UInt(Parameters.DataWidth))
val regs_write_data = Output(UInt(Parameters.DataWidth))
})
io.regs_write_data := MuxLookup(
io.regs_write_source,
io.alu_result,
IndexedSeq(
RegWriteSource.Memory -> io.memory_read_data,
RegWriteSource.CSR -> io.csr_read_data,
RegWriteSource.NextInstructionAddress -> (io.instruction_address + 4.U)
)
)
}

View File

@@ -0,0 +1,103 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_stall
import chisel3._
import chisel3.util.MuxLookup
import riscv.Parameters
object InterruptStatus {
val None = 0x0.U(8.W)
val Timer0 = 0x1.U(8.W)
val Ret = 0xFF.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 {
val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth))
val instruction_ex = Input(UInt(Parameters.InstructionWidth))
val instruction_address_if = Input(UInt(Parameters.AddrWidth))
val instruction_address_id = Input(UInt(Parameters.AddrWidth))
val jump_flag = Input(Bool())
val jump_address = Input(UInt(Parameters.AddrWidth))
val ex_interrupt_handler_address = Output(UInt(Parameters.AddrWidth))
val ex_interrupt_assert = Output(Bool())
val csr_bundle = new CSRDirectAccessBundle
})
val interrupt_enable = io.csr_bundle.mstatus(3)
val jumpping = RegNext(io.jump_flag || io.ex_interrupt_assert)
val instruction_address = Mux(
io.jump_flag,
io.jump_address,
Mux(jumpping, io.instruction_address_if, io.instruction_address_id)
)
val mstatus_disable_interrupt = io.csr_bundle.mstatus(31, 4) ## 0.U(1.W) ## io.csr_bundle.mstatus(2, 0)
val mstatus_recover_interrupt = io.csr_bundle.mstatus(31, 4) ## io.csr_bundle.mstatus(7) ## io.csr_bundle.mstatus(2, 0)
when(io.instruction_ex === InstructionsEnv.ecall || io.instruction_ex === InstructionsEnv.ebreak) {
io.csr_bundle.mstatus_write_data := mstatus_disable_interrupt
io.csr_bundle.mepc_write_data := instruction_address
io.csr_bundle.mcause_write_data := MuxLookup(
io.instruction_ex,
10.U,
IndexedSeq(
InstructionsEnv.ecall -> 11.U,
InstructionsEnv.ebreak -> 3.U,
)
)
io.csr_bundle.direct_write_enable := true.B
io.ex_interrupt_assert := true.B
io.ex_interrupt_handler_address := io.csr_bundle.mtvec
}.elsewhen(io.interrupt_flag =/= InterruptStatus.None && interrupt_enable) {
io.csr_bundle.mstatus_write_data := mstatus_disable_interrupt
io.csr_bundle.mepc_write_data := instruction_address
io.csr_bundle.mcause_write_data := Mux(io.interrupt_flag(0), 0x80000007L.U, 0x8000000BL.U)
io.csr_bundle.direct_write_enable := true.B
io.ex_interrupt_assert := true.B
io.ex_interrupt_handler_address := io.csr_bundle.mtvec
}.elsewhen(io.instruction_ex === InstructionsRet.mret) {
io.csr_bundle.mstatus_write_data := mstatus_recover_interrupt
io.csr_bundle.mepc_write_data := io.csr_bundle.mepc
io.csr_bundle.mcause_write_data := io.csr_bundle.mcause
io.csr_bundle.direct_write_enable := true.B
io.ex_interrupt_assert := true.B
io.ex_interrupt_handler_address := io.csr_bundle.mepc
}.otherwise {
io.csr_bundle.mstatus_write_data := io.csr_bundle.mstatus
io.csr_bundle.mepc_write_data := io.csr_bundle.mepc
io.csr_bundle.mcause_write_data := io.csr_bundle.mcause
io.csr_bundle.direct_write_enable := false.B
io.ex_interrupt_assert := false.B
io.ex_interrupt_handler_address := 0.U
}
}

View File

@@ -0,0 +1,148 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_stall
import chisel3._
import riscv.Parameters
import riscv.core.{CPUBundle, CSR, RegisterFile}
class CPU extends Module {
val io = IO(new CPUBundle)
val ctrl = Module(new Control)
val regs = Module(new RegisterFile)
val inst_fetch = Module(new InstructionFetch)
val if2id = Module(new IF2ID)
val id = Module(new InstructionDecode)
val id2ex = Module(new ID2EX)
val ex = Module(new Execute)
val ex2mem = Module(new EX2MEM)
val mem = Module(new MemoryAccess)
val mem2wb = Module(new MEM2WB)
val wb = Module(new WriteBack)
val clint = Module(new CLINT)
val csr_regs = Module(new CSR)
ctrl.io.jump_flag := ex.io.if_jump_flag
ctrl.io.rs1_id := id.io.regs_reg1_read_address
ctrl.io.rs2_id := id.io.regs_reg2_read_address
ctrl.io.rd_ex := id2ex.io.output_regs_write_address
ctrl.io.reg_write_enable_ex := id2ex.io.output_regs_write_enable
ctrl.io.rd_mem := ex2mem.io.output_regs_write_address
ctrl.io.reg_write_enable_mem := ex2mem.io.output_regs_write_enable
regs.io.write_enable := mem2wb.io.output_regs_write_enable
regs.io.write_address := mem2wb.io.output_regs_write_address
regs.io.write_data := wb.io.regs_write_data
regs.io.read_address1 := id.io.regs_reg1_read_address
regs.io.read_address2 := id.io.regs_reg2_read_address
regs.io.debug_read_address := io.debug_read_address
io.debug_read_data := regs.io.debug_read_data
io.instruction_address := inst_fetch.io.instruction_address
inst_fetch.io.stall_flag_ctrl := ctrl.io.pc_stall
inst_fetch.io.jump_flag_id := ex.io.if_jump_flag
inst_fetch.io.jump_address_id := ex.io.if_jump_address
inst_fetch.io.rom_instruction := io.instruction
inst_fetch.io.instruction_valid := io.instruction_valid
if2id.io.stall := ctrl.io.if2id_stall
if2id.io.flush := ctrl.io.if2id_flush
if2id.io.instruction := inst_fetch.io.id_instruction
if2id.io.instruction_address := inst_fetch.io.instruction_address
if2id.io.interrupt_flag := io.interrupt_flag
id.io.instruction := if2id.io.output_instruction
id2ex.io.flush := ctrl.io.id2ex_flush
id2ex.io.instruction := if2id.io.output_instruction
id2ex.io.instruction_address := if2id.io.output_instruction_address
id2ex.io.reg1_data := regs.io.read_data1
id2ex.io.reg2_data := regs.io.read_data2
id2ex.io.regs_reg1_read_address := id.io.regs_reg1_read_address
id2ex.io.regs_reg2_read_address := id.io.regs_reg2_read_address
id2ex.io.regs_write_enable := id.io.ex_reg_write_enable
id2ex.io.regs_write_address := id.io.ex_reg_write_address
id2ex.io.regs_write_source := id.io.ex_reg_write_source
id2ex.io.immediate := id.io.ex_immediate
id2ex.io.aluop1_source := id.io.ex_aluop1_source
id2ex.io.aluop2_source := id.io.ex_aluop2_source
id2ex.io.csr_write_enable := id.io.ex_csr_write_enable
id2ex.io.csr_address := id.io.ex_csr_address
id2ex.io.memory_read_enable := id.io.ex_memory_read_enable
id2ex.io.memory_write_enable := id.io.ex_memory_write_enable
id2ex.io.csr_read_data := csr_regs.io.id_reg_read_data
ex.io.instruction := id2ex.io.output_instruction
ex.io.instruction_address := id2ex.io.output_instruction_address
ex.io.reg1_data := id2ex.io.output_reg1_data
ex.io.reg2_data := id2ex.io.output_reg2_data
ex.io.immediate_id := id2ex.io.output_immediate
ex.io.aluop1_source_id := id2ex.io.output_aluop1_source
ex.io.aluop2_source_id := id2ex.io.output_aluop2_source
ex.io.csr_read_data_id := id2ex.io.output_csr_read_data
ex.io.interrupt_assert_clint := clint.io.ex_interrupt_assert
ex.io.interrupt_handler_address_clint := clint.io.ex_interrupt_handler_address
ex2mem.io.regs_write_enable := id2ex.io.output_regs_write_enable
ex2mem.io.regs_write_source := id2ex.io.output_regs_write_source
ex2mem.io.regs_write_address := id2ex.io.output_regs_write_address
ex2mem.io.instruction_address := id2ex.io.output_instruction_address
ex2mem.io.funct3 := id2ex.io.output_instruction(14, 12)
ex2mem.io.reg2_data := ex.io.mem_reg2_data
ex2mem.io.memory_read_enable := id2ex.io.output_memory_read_enable
ex2mem.io.memory_write_enable := id2ex.io.output_memory_write_enable
ex2mem.io.alu_result := ex.io.mem_alu_result
ex2mem.io.csr_read_data := id2ex.io.output_csr_read_data
mem.io.alu_result := ex2mem.io.output_alu_result
mem.io.reg2_data := ex2mem.io.output_reg2_data
mem.io.memory_read_enable := ex2mem.io.output_memory_read_enable
mem.io.memory_write_enable := ex2mem.io.output_memory_write_enable
mem.io.funct3 := ex2mem.io.output_funct3
mem.io.regs_write_source := ex2mem.io.output_regs_write_source
mem.io.csr_read_data := ex2mem.io.output_csr_read_data
io.device_select := mem.io.bundle.address(Parameters.AddrBits - 1, Parameters.AddrBits - Parameters.SlaveDeviceCountBits)
io.memory_bundle <> mem.io.bundle
io.memory_bundle.address := 0.U(Parameters.SlaveDeviceCountBits.W) ## mem.io.bundle.address(Parameters.AddrBits - 1 - Parameters.SlaveDeviceCountBits, 0)
mem2wb.io.instruction_address := ex2mem.io.output_instruction_address
mem2wb.io.alu_result := ex2mem.io.output_alu_result
mem2wb.io.regs_write_enable := ex2mem.io.output_regs_write_enable
mem2wb.io.regs_write_source := ex2mem.io.output_regs_write_source
mem2wb.io.regs_write_address := ex2mem.io.output_regs_write_address
mem2wb.io.memory_read_data := mem.io.wb_memory_read_data
mem2wb.io.csr_read_data := ex2mem.io.output_csr_read_data
wb.io.instruction_address := mem2wb.io.output_instruction_address
wb.io.alu_result := mem2wb.io.output_alu_result
wb.io.memory_read_data := mem2wb.io.output_memory_read_data
wb.io.regs_write_source := mem2wb.io.output_regs_write_source
wb.io.csr_read_data := mem2wb.io.output_csr_read_data
clint.io.instruction_address_if := inst_fetch.io.instruction_address
clint.io.instruction_address_id := if2id.io.output_instruction_address
clint.io.instruction_ex := id2ex.io.output_instruction
clint.io.jump_flag := ex.io.clint_jump_flag
clint.io.jump_address := ex.io.clint_jump_address
clint.io.interrupt_flag := if2id.io.output_interrupt_flag
clint.io.csr_bundle <> csr_regs.io.clint_access_bundle
csr_regs.io.reg_read_address_id := id.io.ex_csr_address
csr_regs.io.reg_write_enable_ex := id2ex.io.output_csr_write_enable
csr_regs.io.reg_write_address_ex := id2ex.io.output_csr_address
csr_regs.io.reg_write_data_ex := ex.io.csr_write_data
}

View File

@@ -0,0 +1,46 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_stall
import chisel3._
import riscv.Parameters
class Control extends Module {
val io = IO(new Bundle {
val jump_flag = Input(Bool())
val rs1_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val rs2_id = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val rd_ex = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val reg_write_enable_ex = Input(Bool())
val rd_mem = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val reg_write_enable_mem = Input(Bool())
val if2id_flush = Output(Bool())
val id2ex_flush = Output(Bool())
val pc_stall = Output(Bool())
val if2id_stall = Output(Bool())
})
// Lab3(Stall)
val hazard_from_ex = io.reg_write_enable_ex && io.rd_ex =/= 0.U && (io.rd_ex === io.rs1_id || io.rd_ex === io.rs2_id)
val hazard_from_mem = io.reg_write_enable_mem && io.rd_mem =/= 0.U && (io.rd_mem === io.rs1_id || io.rd_mem === io.rs2_id)
val stall = hazard_from_ex || hazard_from_mem
val flush = io.jump_flag
io.pc_stall := stall && !flush
io.if2id_stall := stall && !flush
io.if2id_flush := flush
io.id2ex_flush := flush || stall
// Lab3(Stall) End
}

View File

@@ -0,0 +1,108 @@
// Copyright 2022 Canbin Huang
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_stall
import chisel3._
import riscv.Parameters
import riscv.core.PipelineRegister
class EX2MEM extends Module {
val io = IO(new Bundle() {
val regs_write_enable = Input(Bool())
val regs_write_source = Input(UInt(2.W))
val regs_write_address = Input(UInt(Parameters.AddrWidth))
val instruction_address = Input(UInt(Parameters.AddrWidth))
val funct3 = Input(UInt(3.W))
val reg2_data = Input(UInt(Parameters.DataWidth))
val memory_read_enable = Input(Bool())
val memory_write_enable = Input(Bool())
val alu_result = Input(UInt(Parameters.DataWidth))
val csr_read_data = Input(UInt(Parameters.DataWidth))
val output_regs_write_enable = Output(Bool())
val output_regs_write_source = Output(UInt(2.W))
val output_regs_write_address = Output(UInt(Parameters.AddrWidth))
val output_instruction_address = Output(UInt(Parameters.AddrWidth))
val output_funct3 = Output(UInt(Parameters.DataWidth))
val output_reg2_data = Output(UInt(Parameters.DataWidth))
val output_memory_read_enable = Output(Bool())
val output_memory_write_enable = Output(Bool())
val output_alu_result = Output(UInt(Parameters.DataWidth))
val output_csr_read_data = Output(UInt(Parameters.DataWidth))
})
val stall = false.B
val flush = false.B
val regs_write_enable = Module(new PipelineRegister(1))
regs_write_enable.io.in := io.regs_write_enable
regs_write_enable.io.stall := stall
regs_write_enable.io.flush := flush
io.output_regs_write_enable := regs_write_enable.io.out
val regs_write_source = Module(new PipelineRegister(2))
regs_write_source.io.in := io.regs_write_source
regs_write_source.io.stall := stall
regs_write_source.io.flush := flush
io.output_regs_write_source := regs_write_source.io.out
val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits))
regs_write_address.io.in := io.regs_write_address
regs_write_address.io.stall := stall
regs_write_address.io.flush := flush
io.output_regs_write_address := regs_write_address.io.out
val instruction_address = Module(new PipelineRegister(Parameters.AddrBits))
instruction_address.io.in := io.instruction_address
instruction_address.io.stall := stall
instruction_address.io.flush := flush
io.output_instruction_address := instruction_address.io.out
val funct3 = Module(new PipelineRegister(3))
funct3.io.in := io.funct3
funct3.io.stall := stall
funct3.io.flush := flush
io.output_funct3 := funct3.io.out
val reg2_data = Module(new PipelineRegister())
reg2_data.io.in := io.reg2_data
reg2_data.io.stall := stall
reg2_data.io.flush := flush
io.output_reg2_data := reg2_data.io.out
val alu_result = Module(new PipelineRegister())
alu_result.io.in := io.alu_result
alu_result.io.stall := stall
alu_result.io.flush := flush
io.output_alu_result := alu_result.io.out
val memory_read_enable = Module(new PipelineRegister(1))
memory_read_enable.io.in := io.memory_read_enable
memory_read_enable.io.stall := stall
memory_read_enable.io.flush := flush
io.output_memory_read_enable := memory_read_enable.io.out
val memory_write_enable = Module(new PipelineRegister(1))
memory_write_enable.io.in := io.memory_write_enable
memory_write_enable.io.stall := stall
memory_write_enable.io.flush := flush
io.output_memory_write_enable := memory_write_enable.io.out
val csr_read_data = Module(new PipelineRegister())
csr_read_data.io.in := io.csr_read_data
csr_read_data.io.stall := stall
csr_read_data.io.flush := flush
io.output_csr_read_data := csr_read_data.io.out
}

View File

@@ -0,0 +1,101 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_stall
import chisel3._
import chisel3.util._
import riscv.Parameters
import riscv.core.{ALU, ALUControl}
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_id = Input(UInt(Parameters.DataWidth))
val aluop1_source_id = Input(UInt(1.W))
val aluop2_source_id = Input(UInt(1.W))
val csr_read_data_id = Input(UInt(Parameters.DataWidth))
val interrupt_assert_clint = Input(Bool())
val interrupt_handler_address_clint = Input(UInt(Parameters.AddrWidth))
val mem_alu_result = Output(UInt(Parameters.DataWidth))
val mem_reg2_data = Output(UInt(Parameters.DataWidth))
val csr_write_data = Output(UInt(Parameters.DataWidth))
val if_jump_flag = Output(Bool())
val if_jump_address = Output(UInt(Parameters.AddrWidth))
val clint_jump_flag = Output(Bool())
val clint_jump_address = Output(UInt(Parameters.AddrWidth))
})
val opcode = io.instruction(6, 0)
val funct3 = io.instruction(14, 12)
val funct7 = io.instruction(31, 25)
val uimm = io.instruction(19, 15)
// ALU compute
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_id === ALUOp1Source.InstructionAddress,
io.instruction_address,
io.reg1_data
)
alu.io.op2 := Mux(
io.aluop2_source_id === ALUOp2Source.Immediate,
io.immediate_id,
io.reg2_data
)
io.mem_alu_result := alu.io.result
io.mem_reg2_data := io.reg2_data
io.csr_write_data := MuxLookup(funct3, 0.U, IndexedSeq(
InstructionsTypeCSR.csrrw -> io.reg1_data,
InstructionsTypeCSR.csrrc -> io.csr_read_data_id.&((~io.reg1_data).asUInt),
InstructionsTypeCSR.csrrs -> io.csr_read_data_id.|(io.reg1_data),
InstructionsTypeCSR.csrrwi -> Cat(0.U(27.W), uimm),
InstructionsTypeCSR.csrrci -> io.csr_read_data_id.&((~Cat(0.U(27.W), uimm)).asUInt),
InstructionsTypeCSR.csrrsi -> io.csr_read_data_id.|(Cat(0.U(27.W), uimm)),
))
// jump and interrupt
val instruction_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.clint_jump_flag := instruction_jump_flag
io.clint_jump_address := alu.io.result
io.if_jump_flag := io.interrupt_assert_clint || instruction_jump_flag
io.if_jump_address := Mux(io.interrupt_assert_clint,
io.interrupt_handler_address_clint,
alu.io.result
)
}

View File

@@ -0,0 +1,164 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_stall
import chisel3._
import riscv.Parameters
import riscv.core.PipelineRegister
class ID2EX extends Module {
val io = IO(new Bundle {
val flush = Input(Bool())
val instruction = Input(UInt(Parameters.InstructionWidth))
val instruction_address = Input(UInt(Parameters.AddrWidth))
val regs_reg1_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val regs_reg2_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val regs_write_enable = Input(Bool())
val regs_write_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val regs_write_source = Input(UInt(2.W))
val reg1_data = Input(UInt(Parameters.DataWidth))
val reg2_data = Input(UInt(Parameters.DataWidth))
val immediate = Input(UInt(Parameters.DataWidth))
val aluop1_source = Input(UInt(1.W))
val aluop2_source = Input(UInt(1.W))
val csr_write_enable = Input(Bool())
val csr_address = Input(UInt(Parameters.CSRRegisterAddrWidth))
val memory_read_enable = Input(Bool())
val memory_write_enable = Input(Bool())
val csr_read_data = Input(UInt(Parameters.DataWidth))
val output_instruction = Output(UInt(Parameters.DataWidth))
val output_instruction_address = Output(UInt(Parameters.AddrWidth))
val output_regs_reg1_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
val output_regs_reg2_read_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
val output_regs_write_enable = Output(Bool())
val output_regs_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
val output_regs_write_source = Output(UInt(2.W))
val output_reg1_data = Output(UInt(Parameters.DataWidth))
val output_reg2_data = Output(UInt(Parameters.DataWidth))
val output_immediate = Output(UInt(Parameters.DataWidth))
val output_aluop1_source = Output(UInt(1.W))
val output_aluop2_source = Output(UInt(1.W))
val output_csr_write_enable = Output(Bool())
val output_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth))
val output_memory_read_enable = Output(Bool())
val output_memory_write_enable = Output(Bool())
val output_csr_read_data = Output(UInt(Parameters.DataWidth))
})
val stall = false.B
val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop))
instruction.io.in := io.instruction
instruction.io.stall := stall
instruction.io.flush := io.flush
io.output_instruction := instruction.io.out
val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress))
instruction_address.io.in := io.instruction_address
instruction_address.io.stall := stall
instruction_address.io.flush := io.flush
io.output_instruction_address := instruction_address.io.out
val regs_reg1_read_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits))
regs_reg1_read_address.io.in := io.regs_reg1_read_address
regs_reg1_read_address.io.stall := stall
regs_reg1_read_address.io.flush := io.flush
io.output_regs_reg1_read_address := regs_reg1_read_address.io.out
val regs_reg2_read_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits))
regs_reg2_read_address.io.in := io.regs_reg2_read_address
regs_reg2_read_address.io.stall := stall
regs_reg2_read_address.io.flush := io.flush
io.output_regs_reg2_read_address := regs_reg2_read_address.io.out
val regs_write_enable = Module(new PipelineRegister(1))
regs_write_enable.io.in := io.regs_write_enable
regs_write_enable.io.stall := stall
regs_write_enable.io.flush := io.flush
io.output_regs_write_enable := regs_write_enable.io.out
val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits))
regs_write_address.io.in := io.regs_write_address
regs_write_address.io.stall := stall
regs_write_address.io.flush := io.flush
io.output_regs_write_address := regs_write_address.io.out
val regs_write_source = Module(new PipelineRegister(2))
regs_write_source.io.in := io.regs_write_source
regs_write_source.io.stall := stall
regs_write_source.io.flush := io.flush
io.output_regs_write_source := regs_write_source.io.out
val reg1_data = Module(new PipelineRegister())
reg1_data.io.in := io.reg1_data
reg1_data.io.stall := stall
reg1_data.io.flush := io.flush
io.output_reg1_data := reg1_data.io.out
val reg2_data = Module(new PipelineRegister())
reg2_data.io.in := io.reg2_data
reg2_data.io.stall := stall
reg2_data.io.flush := io.flush
io.output_reg2_data := reg2_data.io.out
val immediate = Module(new PipelineRegister())
immediate.io.in := io.immediate
immediate.io.stall := stall
immediate.io.flush := io.flush
io.output_immediate := immediate.io.out
val aluop1_source = Module(new PipelineRegister(1))
aluop1_source.io.in := io.aluop1_source
aluop1_source.io.stall := stall
aluop1_source.io.flush := io.flush
io.output_aluop1_source := aluop1_source.io.out
val aluop2_source = Module(new PipelineRegister(1))
aluop2_source.io.in := io.aluop2_source
aluop2_source.io.stall := stall
aluop2_source.io.flush := io.flush
io.output_aluop2_source := aluop2_source.io.out
val csr_write_enable = Module(new PipelineRegister(1))
csr_write_enable.io.in := io.csr_write_enable
csr_write_enable.io.stall := stall
csr_write_enable.io.flush := io.flush
io.output_csr_write_enable := csr_write_enable.io.out
val csr_address = Module(new PipelineRegister(Parameters.CSRRegisterAddrBits))
csr_address.io.in := io.csr_address
csr_address.io.stall := stall
csr_address.io.flush := io.flush
io.output_csr_address := csr_address.io.out
val memory_read_enable = Module(new PipelineRegister(1))
memory_read_enable.io.in := io.memory_read_enable
memory_read_enable.io.stall := stall
memory_read_enable.io.flush := io.flush
io.output_memory_read_enable := memory_read_enable.io.out
val memory_write_enable = Module(new PipelineRegister(1))
memory_write_enable.io.in := io.memory_write_enable
memory_write_enable.io.stall := stall
memory_write_enable.io.flush := io.flush
io.output_memory_write_enable := memory_write_enable.io.out
val csr_read_data = Module(new PipelineRegister())
csr_read_data.io.in := io.csr_read_data
csr_read_data.io.stall := stall
csr_read_data.io.flush := io.flush
io.output_csr_read_data := csr_read_data.io.out
}

View File

@@ -0,0 +1,51 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_stall
import chisel3._
import riscv.Parameters
import riscv.core.PipelineRegister
class IF2ID extends Module {
val io = IO(new Bundle {
val stall = Input(Bool())
val flush = Input(Bool())
val instruction = Input(UInt(Parameters.InstructionWidth))
val instruction_address = Input(UInt(Parameters.AddrWidth))
val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth))
val output_instruction = Output(UInt(Parameters.DataWidth))
val output_instruction_address = Output(UInt(Parameters.AddrWidth))
val output_interrupt_flag = Output(UInt(Parameters.InterruptFlagWidth))
})
val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop))
instruction.io.in := io.instruction
instruction.io.stall := io.stall
instruction.io.flush := io.flush
io.output_instruction := instruction.io.out
val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress))
instruction_address.io.in := io.instruction_address
instruction_address.io.stall := io.stall
instruction_address.io.flush := io.flush
io.output_instruction_address := instruction_address.io.out
val interrupt_flag = Module(new PipelineRegister(Parameters.InterruptFlagBits))
interrupt_flag.io.in := io.interrupt_flag
interrupt_flag.io.stall := io.stall
interrupt_flag.io.flush := io.flush
io.output_interrupt_flag := interrupt_flag.io.out
}

View File

@@ -0,0 +1,214 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_stall
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(Bool())
val ex_aluop2_source = Output(Bool())
val ex_memory_read_enable = Output(Bool())
val ex_memory_write_enable = Output(Bool())
val ex_reg_write_source = Output(UInt(2.W))
val ex_reg_write_enable = Output(Bool())
val ex_reg_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
val ex_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth))
val ex_csr_write_enable = Output(Bool())
})
val 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)
// Lab3(Stall) ID rs
val rs1_used = opcode =/= Instructions.lui && opcode =/= Instructions.auipc && opcode =/= Instructions.jal
val rs2_used = opcode === InstructionTypes.RM || opcode === InstructionTypes.S || opcode === InstructionTypes.B
io.regs_reg1_read_address := Mux(rs1_used, rs1, 0.U)
io.regs_reg2_read_address := Mux(rs2_used, rs2, 0.U)
// Lab3(Stall) ID rs End
io.ex_immediate := MuxLookup(
opcode,
Cat(Fill(20, io.instruction(31)), io.instruction(31, 20)),
IndexedSeq(
InstructionTypes.I -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)),
InstructionTypes.L -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)),
Instructions.jalr -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)),
InstructionTypes.S -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 25), io.instruction(11, 7)),
InstructionTypes.B -> Cat(Fill(20, io.instruction(31)), io.instruction(7), io.instruction(30, 25), io.instruction(11, 8), 0.U(1.W)),
Instructions.lui -> Cat(io.instruction(31, 12), 0.U(12.W)),
Instructions.auipc -> Cat(io.instruction(31, 12), 0.U(12.W)),
Instructions.jal -> Cat(Fill(12, io.instruction(31)), io.instruction(19, 12), io.instruction(20), io.instruction(30, 21), 0.U(1.W))
)
)
io.ex_aluop1_source := Mux(
opcode === Instructions.auipc || opcode === InstructionTypes.B || opcode === Instructions.jal,
ALUOp1Source.InstructionAddress,
ALUOp1Source.Register
)
io.ex_aluop2_source := Mux(
opcode === InstructionTypes.RM,
ALUOp2Source.Register,
ALUOp2Source.Immediate
)
io.ex_memory_read_enable := opcode === InstructionTypes.L
io.ex_memory_write_enable := opcode === InstructionTypes.S
io.ex_reg_write_source := MuxLookup(
opcode,
RegWriteSource.ALUResult,
IndexedSeq(
InstructionTypes.L -> RegWriteSource.Memory,
Instructions.csr -> RegWriteSource.CSR,
Instructions.jal -> RegWriteSource.NextInstructionAddress,
Instructions.jalr -> RegWriteSource.NextInstructionAddress
)
)
// Lab3(Stall) ID rd
val rd_used = opcode === InstructionTypes.RM || opcode === InstructionTypes.I || opcode === InstructionTypes.L ||
opcode === Instructions.lui || opcode === Instructions.auipc || opcode === Instructions.jal ||
opcode === Instructions.jalr || opcode === Instructions.csr
io.ex_reg_write_enable := rd_used
io.ex_reg_write_address := Mux(rd_used, rd, 0.U)
// Lab3(Stall) ID rd End
io.ex_csr_address := io.instruction(31, 20)
io.ex_csr_write_enable := (opcode === Instructions.csr) && (
funct3 === InstructionsTypeCSR.csrrw || funct3 === InstructionsTypeCSR.csrrwi ||
funct3 === InstructionsTypeCSR.csrrs || funct3 === InstructionsTypeCSR.csrrsi ||
funct3 === InstructionsTypeCSR.csrrc || funct3 === InstructionsTypeCSR.csrrci
)
}

View File

@@ -0,0 +1,48 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_stall
import chisel3._
import chisel3.util.MuxCase
import riscv.Parameters
object ProgramCounter {
val EntryAddress = Parameters.EntryAddress
}
class InstructionFetch extends Module {
val io = IO(new Bundle {
val stall_flag_ctrl = Input(Bool())
val jump_flag_id = Input(Bool())
val jump_address_id = Input(UInt(Parameters.AddrWidth))
val rom_instruction = Input(UInt(Parameters.DataWidth))
val instruction_valid = Input(Bool())
val instruction_address = Output(UInt(Parameters.AddrWidth))
val id_instruction = Output(UInt(Parameters.InstructionWidth))
})
val pc = RegInit(ProgramCounter.EntryAddress)
pc := MuxCase(
pc + 4.U,
IndexedSeq(
(io.jump_flag_id && !io.stall_flag_ctrl) -> io.jump_address_id,
(io.stall_flag_ctrl || !io.instruction_valid) -> pc
)
)
io.instruction_address := pc
io.id_instruction := Mux(io.instruction_valid, io.rom_instruction, InstructionsNop.nop)
}

View File

@@ -0,0 +1,83 @@
// Copyright 2022 Canbin Huang
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_stall
import chisel3._
import riscv.Parameters
import riscv.core.PipelineRegister
class MEM2WB extends Module {
val io = IO(new Bundle() {
val instruction_address = Input(UInt(Parameters.AddrWidth))
val alu_result = Input(UInt(Parameters.DataWidth))
val regs_write_enable = Input(Bool())
val regs_write_source = Input(UInt(2.W))
val regs_write_address = Input(UInt(Parameters.AddrWidth))
val memory_read_data = Input(UInt(Parameters.DataWidth))
val csr_read_data = Input(UInt(Parameters.DataWidth))
val output_instruction_address = Output(UInt(Parameters.AddrWidth))
val output_alu_result = Output(UInt(Parameters.DataWidth))
val output_regs_write_enable = Output(Bool())
val output_regs_write_source = Output(UInt(2.W))
val output_regs_write_address = Output(UInt(Parameters.AddrWidth))
val output_memory_read_data = Output(UInt(Parameters.DataWidth))
val output_csr_read_data = Output(UInt(Parameters.DataWidth))
})
val stall = false.B
val flush = false.B
val alu_result = Module(new PipelineRegister())
alu_result.io.in := io.alu_result
alu_result.io.stall := stall
alu_result.io.flush := flush
io.output_alu_result := alu_result.io.out
val memory_read_data = Module(new PipelineRegister())
memory_read_data.io.in := io.memory_read_data
memory_read_data.io.stall := stall
memory_read_data.io.flush := flush
io.output_memory_read_data := memory_read_data.io.out
val regs_write_enable = Module(new PipelineRegister(1))
regs_write_enable.io.in := io.regs_write_enable
regs_write_enable.io.stall := stall
regs_write_enable.io.flush := flush
io.output_regs_write_enable := regs_write_enable.io.out
val regs_write_source = Module(new PipelineRegister(2))
regs_write_source.io.in := io.regs_write_source
regs_write_source.io.stall := stall
regs_write_source.io.flush := flush
io.output_regs_write_source := regs_write_source.io.out
val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits))
regs_write_address.io.in := io.regs_write_address
regs_write_address.io.stall := stall
regs_write_address.io.flush := flush
io.output_regs_write_address := regs_write_address.io.out
val instruction_address = Module(new PipelineRegister(Parameters.InstructionBits))
instruction_address.io.in := io.instruction_address
instruction_address.io.stall := stall
instruction_address.io.flush := flush
io.output_instruction_address := instruction_address.io.out
val csr_read_data = Module(new PipelineRegister())
csr_read_data.io.in := io.csr_read_data
csr_read_data.io.stall := stall
csr_read_data.io.flush := flush
io.output_csr_read_data := csr_read_data.io.out
}

View File

@@ -0,0 +1,106 @@
// Copyright 2022 Canbin Huang
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_stall
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 regs_write_source = Input(UInt(2.W))
val csr_read_data = Input(UInt(Parameters.DataWidth))
val wb_memory_read_data = Output(UInt(Parameters.DataWidth))
val bundle = Flipped(new RAMBundle)
})
val mem_address_index = io.alu_result(log2Up(Parameters.WordSize) - 1, 0).asUInt
io.bundle.write_enable := io.memory_write_enable
io.bundle.write_data := 0.U
io.bundle.address := io.alu_result
io.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.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.bundle.write_data := io.reg2_data
io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B))
when(io.funct3 === InstructionsTypeS.sb) {
io.bundle.write_strobe(mem_address_index) := true.B
io.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.bundle.write_strobe(i) := true.B
}
io.bundle.write_data := io.reg2_data(Parameters.WordSize / 2 * Parameters.ByteBits, 0)
}.otherwise {
for (i <- Parameters.WordSize / 2 until Parameters.WordSize) {
io.bundle.write_strobe(i) := true.B
}
io.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.bundle.write_strobe(i) := true.B
}
}
}
}

View File

@@ -0,0 +1,40 @@
// Copyright 2022 Canbin Huang
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.fivestage_stall
import chisel3._
import chisel3.util._
import riscv.Parameters
class WriteBack extends Module {
val io = IO(new Bundle() {
val instruction_address = Input(UInt(Parameters.AddrWidth))
val alu_result = Input(UInt(Parameters.DataWidth))
val memory_read_data = Input(UInt(Parameters.DataWidth))
val regs_write_source = Input(UInt(2.W))
val csr_read_data = Input(UInt(Parameters.DataWidth))
val regs_write_data = Output(UInt(Parameters.DataWidth))
})
io.regs_write_data := MuxLookup(
io.regs_write_source,
io.alu_result,
IndexedSeq(
RegWriteSource.Memory -> io.memory_read_data,
RegWriteSource.CSR -> io.csr_read_data,
RegWriteSource.NextInstructionAddress -> (io.instruction_address + 4.U)
)
)
}

View File

@@ -0,0 +1,88 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.threestage
import chisel3._
import chisel3.util.MuxLookup
import riscv.Parameters
object InterruptStatus {
val None = 0x0.U(8.W)
val Timer0 = 0x1.U(8.W)
val Ret = 0xFF.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 {
val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth))
val instruction_ex = Input(UInt(Parameters.InstructionWidth))
val instruction_address_if = Input(UInt(Parameters.AddrWidth))
val instruction_address_id = Input(UInt(Parameters.AddrWidth))
val jump_flag = Input(Bool())
val jump_address = Input(UInt(Parameters.AddrWidth))
val ex_interrupt_handler_address = Output(UInt(Parameters.AddrWidth))
val ex_interrupt_assert = Output(Bool())
val csr_bundle = new CSRDirectAccessBundle
})
val interrupt_enable = io.csr_bundle.mstatus(3)
val jumpping = RegNext(io.jump_flag || io.ex_interrupt_assert)
val instruction_address = Mux(
io.jump_flag,
io.jump_address,
Mux(jumpping, io.instruction_address_if, io.instruction_address_id)
)
val mstatus_disable_interrupt = io.csr_bundle.mstatus(31, 4) ## 0.U(1.W) ## io.csr_bundle.mstatus(2, 0)
val mstatus_recover_interrupt = io.csr_bundle.mstatus(31, 4) ## io.csr_bundle.mstatus(7) ## io.csr_bundle.mstatus(2, 0)
val exception = io.instruction_ex === InstructionsEnv.ecall || io.instruction_ex === InstructionsEnv.ebreak
val interrupt = io.interrupt_flag =/= InterruptStatus.None && interrupt_enable
val mret = io.instruction_ex === InstructionsRet.mret
val interrupt_assert = exception || interrupt || mret
io.csr_bundle.mstatus_write_data := Mux(mret, mstatus_recover_interrupt, mstatus_disable_interrupt)
io.csr_bundle.mepc_write_data := instruction_address
io.csr_bundle.mcause_write_data := Mux(
exception,
MuxLookup(
io.instruction_ex,
10.U,
IndexedSeq(
InstructionsEnv.ecall -> 11.U,
InstructionsEnv.ebreak -> 3.U,
)
),
Mux(io.interrupt_flag(0), 0x80000007L.U, 0x8000000BL.U)
)
io.csr_bundle.direct_write_enable := interrupt_assert
io.ex_interrupt_assert := interrupt_assert
io.ex_interrupt_handler_address := Mux(mret, io.csr_bundle.mepc, io.csr_bundle.mtvec)
}

View 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.threestage
import chisel3._
import riscv.Parameters
import riscv.core.{CPUBundle, CSR, RegisterFile}
class CPU extends Module {
val io = IO(new CPUBundle)
val ctrl = Module(new Control)
val regs = Module(new RegisterFile)
val inst_fetch = Module(new InstructionFetch)
val if2id = Module(new IF2ID)
val id = Module(new InstructionDecode)
val id2ex = Module(new ID2EX)
val ex = Module(new Execute)
val clint = Module(new CLINT)
val csr_regs = Module(new CSR)
// Lab3(ThreeStage)
// if2id.io.flush := false.B
// id2ex.io.flush := false.B
ctrl.io.jump_flag_ex := ex.io.if_jump_flag
if2id.io.flush := ctrl.io.if2id_flush
id2ex.io.flush := ctrl.io.id2ex_flush
// Lab3(ThreeStage) End
regs.io.write_enable := id2ex.io.output_regs_write_enable
regs.io.write_address := id2ex.io.output_regs_write_address
regs.io.write_data := ex.io.regs_write_data
regs.io.read_address1 := id.io.regs_reg1_read_address
regs.io.read_address2 := id.io.regs_reg2_read_address
regs.io.debug_read_address := io.debug_read_address
io.debug_read_data := regs.io.debug_read_data
io.instruction_address := inst_fetch.io.instruction_address
inst_fetch.io.jump_flag_ex := ex.io.if_jump_flag
inst_fetch.io.jump_address_ex := ex.io.if_jump_address
inst_fetch.io.rom_instruction := io.instruction
inst_fetch.io.instruction_valid := io.instruction_valid
if2id.io.instruction := inst_fetch.io.id_instruction
if2id.io.instruction_address := inst_fetch.io.instruction_address
if2id.io.interrupt_flag := io.interrupt_flag
id.io.instruction := if2id.io.output_instruction
id2ex.io.instruction := if2id.io.output_instruction
id2ex.io.instruction_address := if2id.io.output_instruction_address
id2ex.io.reg1_data := regs.io.read_data1
id2ex.io.reg2_data := regs.io.read_data2
id2ex.io.regs_write_enable := id.io.ex_reg_write_enable
id2ex.io.regs_write_address := id.io.ex_reg_write_address
id2ex.io.regs_write_source := id.io.ex_reg_write_source
id2ex.io.immediate := id.io.ex_immediate
id2ex.io.aluop1_source := id.io.ex_aluop1_source
id2ex.io.aluop2_source := id.io.ex_aluop2_source
id2ex.io.csr_write_enable := id.io.ex_csr_write_enable
id2ex.io.csr_address := id.io.ex_csr_address
id2ex.io.memory_read_enable := id.io.ex_memory_read_enable
id2ex.io.memory_write_enable := id.io.ex_memory_write_enable
id2ex.io.csr_read_data := csr_regs.io.id_reg_read_data
ex.io.instruction := id2ex.io.output_instruction
ex.io.instruction_address := id2ex.io.output_instruction_address
ex.io.reg1_data := id2ex.io.output_reg1_data
ex.io.reg2_data := id2ex.io.output_reg2_data
ex.io.csr_read_data := id2ex.io.output_csr_read_data
ex.io.immediate_id := id2ex.io.output_immediate
ex.io.aluop1_source_id := id2ex.io.output_aluop1_source
ex.io.aluop2_source_id := id2ex.io.output_aluop2_source
ex.io.memory_read_enable_id := id2ex.io.output_memory_read_enable
ex.io.memory_write_enable_id := id2ex.io.output_memory_write_enable
ex.io.regs_write_source_id := id2ex.io.output_regs_write_source
ex.io.interrupt_assert_clint := clint.io.ex_interrupt_assert
ex.io.interrupt_handler_address_clint := clint.io.ex_interrupt_handler_address
io.device_select := ex.io.memory_bundle.address(Parameters.AddrBits - 1, Parameters.AddrBits - Parameters.SlaveDeviceCountBits)
io.memory_bundle <> ex.io.memory_bundle
io.memory_bundle.address := 0.U(Parameters.SlaveDeviceCountBits.W) ## ex.io.memory_bundle.address(Parameters.AddrBits - 1 - Parameters.SlaveDeviceCountBits, 0)
clint.io.instruction_address_if := inst_fetch.io.instruction_address
clint.io.instruction_address_id := if2id.io.output_instruction_address
clint.io.instruction_ex := id2ex.io.output_instruction
clint.io.jump_flag := ex.io.clint_jump_flag
clint.io.jump_address := ex.io.clint_jump_address
clint.io.interrupt_flag := if2id.io.output_interrupt_flag
clint.io.csr_bundle <> csr_regs.io.clint_access_bundle
csr_regs.io.reg_read_address_id := id.io.ex_csr_address
csr_regs.io.reg_write_enable_ex := id2ex.io.output_csr_write_enable
csr_regs.io.reg_write_address_ex := id2ex.io.output_csr_address
csr_regs.io.reg_write_data_ex := ex.io.csr_write_data
}

View File

@@ -0,0 +1,30 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.threestage
import chisel3._
class Control extends Module {
// Lab3(ThreeStage)
val io = IO(new Bundle {
val jump_flag_ex = Input(Bool())
val if2id_flush = Output(Bool())
val id2ex_flush = Output(Bool())
})
val flush = io.jump_flag_ex
io.if2id_flush := flush
io.id2ex_flush := flush
// Lab3(ThreeStage) End
}

View File

@@ -0,0 +1,191 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.threestage
import chisel3._
import chisel3.util._
import peripheral.RAMBundle
import riscv.Parameters
import riscv.core.{ALU, ALUControl}
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 csr_read_data = Input(UInt(Parameters.DataWidth))
val immediate_id = Input(UInt(Parameters.DataWidth))
val aluop1_source_id = Input(UInt(1.W))
val aluop2_source_id = Input(UInt(1.W))
val memory_read_enable_id = Input(Bool())
val memory_write_enable_id = Input(Bool())
val regs_write_source_id = Input(UInt(2.W))
val interrupt_assert_clint = Input(Bool())
val interrupt_handler_address_clint = Input(UInt(Parameters.AddrWidth))
val memory_bundle = Flipped(new RAMBundle)
val csr_write_data = Output(UInt(Parameters.DataWidth))
val regs_write_data = Output(UInt(Parameters.DataWidth))
val if_jump_flag = Output(Bool())
val if_jump_address = Output(UInt(Parameters.AddrWidth))
val clint_jump_flag = Output(Bool())
val clint_jump_address = Output(UInt(Parameters.AddrWidth))
})
val opcode = io.instruction(6, 0)
val funct3 = io.instruction(14, 12)
val funct7 = io.instruction(31, 25)
val uimm = io.instruction(19, 15)
// ALU compute
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_id === ALUOp1Source.InstructionAddress,
io.instruction_address,
io.reg1_data
)
alu.io.op2 := Mux(
io.aluop2_source_id === ALUOp2Source.Immediate,
io.immediate_id,
io.reg2_data
)
io.csr_write_data := MuxLookup(
funct3,
0.U,
IndexedSeq(
InstructionsTypeCSR.csrrw -> io.reg1_data,
InstructionsTypeCSR.csrrc -> (io.csr_read_data & (~io.reg1_data).asUInt),
InstructionsTypeCSR.csrrs -> (io.csr_read_data | io.reg1_data),
InstructionsTypeCSR.csrrwi -> (0.U(27.W) ## uimm),
InstructionsTypeCSR.csrrci -> (io.csr_read_data & (~(0.U(27.W) ## uimm)).asUInt),
InstructionsTypeCSR.csrrsi -> (io.csr_read_data | 0.U(27.W) ## uimm),
)
)
// memory access
val mem_address_index = alu.io.result(log2Up(Parameters.WordSize) - 1, 0).asUInt
val mem_read_data = Wire(UInt(Parameters.DataWidth))
io.memory_bundle.write_enable := io.memory_write_enable_id
io.memory_bundle.write_data := 0.U
io.memory_bundle.address := alu.io.result
io.memory_bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B))
mem_read_data := 0.U
when(io.memory_read_enable_id) {
val data = io.memory_bundle.read_data
mem_read_data := MuxLookup(
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_id) {
io.memory_bundle.write_data := io.reg2_data
io.memory_bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B))
when(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(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(funct3 === InstructionsTypeS.sw) {
for (i <- 0 until Parameters.WordSize) {
io.memory_bundle.write_strobe(i) := true.B
}
}
}
// write back
io.regs_write_data := MuxLookup(
io.regs_write_source_id,
alu.io.result,
IndexedSeq(
RegWriteSource.Memory -> mem_read_data,
RegWriteSource.CSR -> io.csr_read_data,
RegWriteSource.NextInstructionAddress -> (io.instruction_address + 4.U)
)
)
// jump and interrupt
val instruction_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.clint_jump_flag := instruction_jump_flag
io.clint_jump_address := alu.io.result
io.if_jump_flag := io.interrupt_assert_clint || instruction_jump_flag
io.if_jump_address := Mux(io.interrupt_assert_clint,
io.interrupt_handler_address_clint,
alu.io.result
)
}

View File

@@ -0,0 +1,148 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.threestage
import chisel3._
import riscv.Parameters
import riscv.core.PipelineRegister
class ID2EX extends Module {
val io = IO(new Bundle {
val flush = Input(Bool())
val instruction = Input(UInt(Parameters.InstructionWidth))
val instruction_address = Input(UInt(Parameters.AddrWidth))
val regs_write_enable = Input(Bool())
val regs_write_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val regs_write_source = Input(UInt(2.W))
val reg1_data = Input(UInt(Parameters.DataWidth))
val reg2_data = Input(UInt(Parameters.DataWidth))
val immediate = Input(UInt(Parameters.DataWidth))
val aluop1_source = Input(UInt(1.W))
val aluop2_source = Input(UInt(1.W))
val csr_write_enable = Input(Bool())
val csr_address = Input(UInt(Parameters.CSRRegisterAddrWidth))
val memory_read_enable = Input(Bool())
val memory_write_enable = Input(Bool())
val csr_read_data = Input(UInt(Parameters.DataWidth))
val output_instruction = Output(UInt(Parameters.DataWidth))
val output_instruction_address = Output(UInt(Parameters.AddrWidth))
val output_regs_write_enable = Output(Bool())
val output_regs_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
val output_regs_write_source = Output(UInt(2.W))
val output_reg1_data = Output(UInt(Parameters.DataWidth))
val output_reg2_data = Output(UInt(Parameters.DataWidth))
val output_immediate = Output(UInt(Parameters.DataWidth))
val output_aluop1_source = Output(UInt(1.W))
val output_aluop2_source = Output(UInt(1.W))
val output_csr_write_enable = Output(Bool())
val output_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth))
val output_memory_read_enable = Output(Bool())
val output_memory_write_enable = Output(Bool())
val output_csr_read_data = Output(UInt(Parameters.DataWidth))
})
val stall = false.B
val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop))
instruction.io.in := io.instruction
instruction.io.stall := stall
instruction.io.flush := io.flush
io.output_instruction := instruction.io.out
val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress))
instruction_address.io.in := io.instruction_address
instruction_address.io.stall := stall
instruction_address.io.flush := io.flush
io.output_instruction_address := instruction_address.io.out
val regs_write_enable = Module(new PipelineRegister(1))
regs_write_enable.io.in := io.regs_write_enable
regs_write_enable.io.stall := stall
regs_write_enable.io.flush := io.flush
io.output_regs_write_enable := regs_write_enable.io.out
val regs_write_address = Module(new PipelineRegister(Parameters.PhysicalRegisterAddrBits))
regs_write_address.io.in := io.regs_write_address
regs_write_address.io.stall := stall
regs_write_address.io.flush := io.flush
io.output_regs_write_address := regs_write_address.io.out
val regs_write_source = Module(new PipelineRegister(2))
regs_write_source.io.in := io.regs_write_source
regs_write_source.io.stall := stall
regs_write_source.io.flush := io.flush
io.output_regs_write_source := regs_write_source.io.out
val reg1_data = Module(new PipelineRegister())
reg1_data.io.in := io.reg1_data
reg1_data.io.stall := stall
reg1_data.io.flush := io.flush
io.output_reg1_data := reg1_data.io.out
val reg2_data = Module(new PipelineRegister())
reg2_data.io.in := io.reg2_data
reg2_data.io.stall := stall
reg2_data.io.flush := io.flush
io.output_reg2_data := reg2_data.io.out
val immediate = Module(new PipelineRegister())
immediate.io.in := io.immediate
immediate.io.stall := stall
immediate.io.flush := io.flush
io.output_immediate := immediate.io.out
val aluop1_source = Module(new PipelineRegister(1))
aluop1_source.io.in := io.aluop1_source
aluop1_source.io.stall := stall
aluop1_source.io.flush := io.flush
io.output_aluop1_source := aluop1_source.io.out
val aluop2_source = Module(new PipelineRegister(1))
aluop2_source.io.in := io.aluop2_source
aluop2_source.io.stall := stall
aluop2_source.io.flush := io.flush
io.output_aluop2_source := aluop2_source.io.out
val csr_write_enable = Module(new PipelineRegister(1))
csr_write_enable.io.in := io.csr_write_enable
csr_write_enable.io.stall := stall
csr_write_enable.io.flush := io.flush
io.output_csr_write_enable := csr_write_enable.io.out
val csr_address = Module(new PipelineRegister(Parameters.CSRRegisterAddrBits))
csr_address.io.in := io.csr_address
csr_address.io.stall := stall
csr_address.io.flush := io.flush
io.output_csr_address := csr_address.io.out
val memory_read_enable = Module(new PipelineRegister(1))
memory_read_enable.io.in := io.memory_read_enable
memory_read_enable.io.stall := stall
memory_read_enable.io.flush := io.flush
io.output_memory_read_enable := memory_read_enable.io.out
val memory_write_enable = Module(new PipelineRegister(1))
memory_write_enable.io.in := io.memory_write_enable
memory_write_enable.io.stall := stall
memory_write_enable.io.flush := io.flush
io.output_memory_write_enable := memory_write_enable.io.out
val csr_read_data = Module(new PipelineRegister())
csr_read_data.io.in := io.csr_read_data
csr_read_data.io.stall := stall
csr_read_data.io.flush := io.flush
io.output_csr_read_data := csr_read_data.io.out
}

View File

@@ -0,0 +1,52 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.threestage
import chisel3._
import riscv.Parameters
import riscv.core.PipelineRegister
class IF2ID extends Module {
val io = IO(new Bundle {
val flush = Input(Bool())
val instruction = Input(UInt(Parameters.InstructionWidth))
val instruction_address = Input(UInt(Parameters.AddrWidth))
val interrupt_flag = Input(UInt(Parameters.InterruptFlagWidth))
val output_instruction = Output(UInt(Parameters.DataWidth))
val output_instruction_address = Output(UInt(Parameters.AddrWidth))
val output_interrupt_flag = Output(UInt(Parameters.InterruptFlagWidth))
})
val stall = false.B
val instruction = Module(new PipelineRegister(defaultValue = InstructionsNop.nop))
instruction.io.in := io.instruction
instruction.io.stall := stall
instruction.io.flush := io.flush
io.output_instruction := instruction.io.out
val instruction_address = Module(new PipelineRegister(defaultValue = ProgramCounter.EntryAddress))
instruction_address.io.in := io.instruction_address
instruction_address.io.stall := stall
instruction_address.io.flush := io.flush
io.output_instruction_address := instruction_address.io.out
val interrupt_flag = Module(new PipelineRegister(Parameters.InterruptFlagBits))
interrupt_flag.io.in := io.interrupt_flag
interrupt_flag.io.stall := stall
interrupt_flag.io.flush := io.flush
io.output_interrupt_flag := interrupt_flag.io.out
}

View File

@@ -0,0 +1,207 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.threestage
import chisel3._
import chisel3.util._
import riscv.Parameters
object InstructionTypes {
val L = "b0000011".U
val I = "b0010011".U
val S = "b0100011".U
val RM = "b0110011".U
val B = "b1100011".U
}
object Instructions {
val lui = "b0110111".U
val nop = "b0000001".U
val jal = "b1101111".U
val jalr = "b1100111".U
val auipc = "b0010111".U
val csr = "b1110011".U
val fence = "b0001111".U
}
object InstructionsTypeL {
val lb = "b000".U
val lh = "b001".U
val lw = "b010".U
val lbu = "b100".U
val lhu = "b101".U
}
object InstructionsTypeI {
val addi = 0.U
val slli = 1.U
val slti = 2.U
val sltiu = 3.U
val xori = 4.U
val sri = 5.U
val ori = 6.U
val andi = 7.U
}
object InstructionsTypeS {
val sb = "b000".U
val sh = "b001".U
val sw = "b010".U
}
object InstructionsTypeR {
val add_sub = 0.U
val sll = 1.U
val slt = 2.U
val sltu = 3.U
val xor = 4.U
val sr = 5.U
val or = 6.U
val and = 7.U
}
object InstructionsTypeM {
val mul = 0.U
val mulh = 1.U
val mulhsu = 2.U
val mulhum = 3.U
val div = 4.U
val divu = 5.U
val rem = 6.U
val remu = 7.U
}
object InstructionsTypeB {
val beq = "b000".U
val bne = "b001".U
val blt = "b100".U
val bge = "b101".U
val bltu = "b110".U
val bgeu = "b111".U
}
object InstructionsTypeCSR {
val csrrw = "b001".U
val csrrs = "b010".U
val csrrc = "b011".U
val csrrwi = "b101".U
val csrrsi = "b110".U
val csrrci = "b111".U
}
object InstructionsNop {
val nop = 0x00000013L.U(Parameters.DataWidth)
}
object InstructionsRet {
val mret = 0x30200073L.U(Parameters.DataWidth)
val ret = 0x00008067L.U(Parameters.DataWidth)
}
object InstructionsEnv {
val ecall = 0x00000073L.U(Parameters.DataWidth)
val ebreak = 0x00100073L.U(Parameters.DataWidth)
}
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(Bool())
val ex_aluop2_source = Output(Bool())
val ex_memory_read_enable = Output(Bool())
val ex_memory_write_enable = Output(Bool())
val ex_reg_write_source = Output(UInt(2.W))
val ex_reg_write_enable = Output(Bool())
val ex_reg_write_address = Output(UInt(Parameters.PhysicalRegisterAddrWidth))
val ex_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth))
val ex_csr_write_enable = Output(Bool())
})
val opcode = io.instruction(6, 0)
val funct3 = io.instruction(14, 12)
val funct7 = io.instruction(31, 25)
val rd = io.instruction(11, 7)
val rs1 = io.instruction(19, 15)
val rs2 = io.instruction(24, 20)
io.regs_reg1_read_address := Mux(opcode === Instructions.lui, 0.U(Parameters.PhysicalRegisterAddrWidth), rs1)
io.regs_reg2_read_address := rs2
io.ex_immediate := MuxLookup(
opcode,
Cat(Fill(20, io.instruction(31)), io.instruction(31, 20)),
IndexedSeq(
InstructionTypes.I -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)),
InstructionTypes.L -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)),
Instructions.jalr -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 20)),
InstructionTypes.S -> Cat(Fill(21, io.instruction(31)), io.instruction(30, 25), io.instruction(11, 7)),
InstructionTypes.B -> Cat(Fill(20, io.instruction(31)), io.instruction(7), io.instruction(30, 25), io.instruction(11, 8), 0.U(1.W)),
Instructions.lui -> Cat(io.instruction(31, 12), 0.U(12.W)),
Instructions.auipc -> Cat(io.instruction(31, 12), 0.U(12.W)),
Instructions.jal -> Cat(Fill(12, io.instruction(31)), io.instruction(19, 12), io.instruction(20), io.instruction(30, 21), 0.U(1.W))
)
)
io.ex_aluop1_source := Mux(
opcode === Instructions.auipc || opcode === InstructionTypes.B || opcode === Instructions.jal,
ALUOp1Source.InstructionAddress,
ALUOp1Source.Register
)
io.ex_aluop2_source := Mux(
opcode === InstructionTypes.RM,
ALUOp2Source.Register,
ALUOp2Source.Immediate
)
io.ex_memory_read_enable := opcode === InstructionTypes.L
io.ex_memory_write_enable := opcode === InstructionTypes.S
io.ex_reg_write_source := MuxLookup(
opcode,
RegWriteSource.ALUResult,
IndexedSeq(
InstructionTypes.L -> RegWriteSource.Memory,
Instructions.csr -> RegWriteSource.CSR,
Instructions.jal -> RegWriteSource.NextInstructionAddress,
Instructions.jalr -> RegWriteSource.NextInstructionAddress
)
)
io.ex_reg_write_enable := (opcode === InstructionTypes.RM) || (opcode === InstructionTypes.I) ||
(opcode === InstructionTypes.L) || (opcode === Instructions.auipc) || (opcode === Instructions.lui) ||
(opcode === Instructions.jal) || (opcode === Instructions.jalr) || (opcode === Instructions.csr)
io.ex_reg_write_address := rd
io.ex_csr_address := io.instruction(31, 20)
io.ex_csr_write_enable := (opcode === Instructions.csr) && (
funct3 === InstructionsTypeCSR.csrrw || funct3 === InstructionsTypeCSR.csrrwi ||
funct3 === InstructionsTypeCSR.csrrs || funct3 === InstructionsTypeCSR.csrrsi ||
funct3 === InstructionsTypeCSR.csrrc || funct3 === InstructionsTypeCSR.csrrci
)
}

View File

@@ -0,0 +1,47 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.core.threestage
import chisel3._
import chisel3.util.MuxCase
import riscv.Parameters
object ProgramCounter {
val EntryAddress = Parameters.EntryAddress
}
class InstructionFetch extends Module {
val io = IO(new Bundle {
val jump_flag_ex = Input(Bool())
val jump_address_ex = Input(UInt(Parameters.AddrWidth))
val rom_instruction = Input(UInt(Parameters.DataWidth))
val instruction_valid = Input(Bool())
val instruction_address = Output(UInt(Parameters.AddrWidth))
val id_instruction = Output(UInt(Parameters.InstructionWidth))
})
val pc = RegInit(ProgramCounter.EntryAddress)
pc := MuxCase(
pc,
IndexedSeq(
io.jump_flag_ex -> io.jump_address_ex,
io.instruction_valid -> (pc + 4.U)
)
)
io.instruction_address := pc
io.id_instruction := Mux(io.instruction_valid, io.rom_instruction, InstructionsNop.nop)
}