blob: 47e8fb5c8f29513b89ec8f6d2408e5e0fab34d83 [file] [log] [blame]
// SPDX-FileCopyrightText: 2020 Muhammad Hadir Khan
//
// 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.
// SPDX-License-Identifier: Apache-2.0
package core
import chisel3._
import chisel3.util._
import main.scala.core.csrs.{Exc_Cause}
class Fetch extends Module {
val io = IO(new Bundle {
// ------------------------------------ //
// instruction memory interface(inputs) //
// ------------------------------------ //
val core_instr_gnt_i = Input(Bool())
val core_instr_rvalid_i = Input(Bool())
val core_instr_rdata_i = Input(UInt(32.W))
// ------------------------------------ //
// csr register file(inputs/outputs) //
// ------------------------------------ //
val csrRegFile_irq_pending_i = Input(Bool())
val csrRegFile_csr_mstatus_mie_i = Input(Bool())
val csrRegFile_csr_mtvec_i = Input(UInt(32.W))
val csrRegFile_csr_mtvec_init_o = Output(Bool())
val csrRegFile_csr_save_cause_o = Output(Bool())
val csrRegFile_csr_save_if_o = Output(Bool())
val csrRegFile_csr_if_pc_o = Output(UInt(32.W))
val csrRegFile_exc_cause_o = Output(UInt(6.W))
val csrRegFile_csr_mepc_i = Input(UInt(32.W))
val core_init_mtvec_i = Input(Bool())
val decode_sb_imm_i = Input(SInt(32.W))
val decode_uj_imm_i = Input(SInt(32.W))
val decode_jalr_imm_i = Input(SInt(32.W))
val decode_ctrl_next_pc_sel_i = Input(UInt(2.W))
val decode_ctrl_out_branch_i = Input(UInt(1.W))
val decode_branchLogic_output_i = Input(UInt(1.W))
val decode_hazardDetection_pc_i = Input(SInt(32.W))
val decode_hazardDetection_inst_i = Input(UInt(32.W))
val decode_hazardDetection_current_pc_i = Input(SInt(32.W))
val decode_hazardDetection_pc_forward_i = Input(UInt(1.W))
val decode_hazardDetection_inst_forward_i = Input(UInt(1.W))
// true when mret instruction decoded in decoded stage
val decode_mret_inst_i = Input(Bool())
val core_stall_i = Input(Bool())
// ------------------------------------- //
// instruction memory interface(outputs) //
// ------------------------------------- //
val core_instr_addr_o = Output(UInt(32.W))
val core_instr_req_o = Output(Bool())
// ------------------------------------- //
// decode stage (outputs) //
// ------------------------------------- //
val decode_if_id_pc_o = Output(SInt(32.W))
val decode_if_id_pc4_o = Output(SInt(32.W))
val decode_if_id_inst_o = Output(UInt(32.W))
})
// ____________________s???s???s???s
// ___________________s$$$$$$s..s..?..?..?
// __________________$$$$$$$$$$$$s..s.?..?
// ____________________$$$$$$$$$$$$$$s…?
// ______________ s$$$$$$(O)$$$$$$$$$$$$.?
// ____________ €$$$$$$$$$$$$$$$$$$$$s..?..s
// _____________s$$$$$$$$$$$$$$$$$$$$$$s..?
// _____________________s$$$$$$$$$$$$$$..s..?
// ______________________$$$$$$$$$$$$s..s..?
// ______________________$$$$$$$$$$$$.s.?.s.?
// _____________________$$$$$$$$$$$$$s..s….?
// ____________________$$$$$$$$$$$$$$s_??s.?
// ___________________$$$$$$$$$$$$$$$s.s….?
// _____s$$$$________$$$$$$$$$$$$$$$$$..s?
// ____$$$$$$$$_____$$$$$$$$$$$$$$$$$$s…s
// ____$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$_s_?__s$s
// ____$$__$$$$$$$$$$$$$$$$$$$$$$$$$$_____s$$$
// ____$$____$$$$$$$$$$$$$$$$$$$$$$s_____s$$$$s
// ___$$$$$$$$$$$$$$$$$$$$$$$$$$_$$_____s$$$$$$
// __$$$$$$$$$$$$$$$$$$$$$$$$$$$$_$____s$$$$$$$
// __$$$$__$$$$$$$$$$$$$$$$$$$$$$$____s$$$$$$$$
// ___$$$________$$$$$$$$$$$$$$$$$$___s$$$$$$$
// ____$$$s______$$$$$$$$$$$$$$$$$$$__s$$$$$$
// _____$$$_______$$$$$$$$$$$$$$$$$$$_s$$
val NOP = "b00000000000000000000000000010011".U(32.W) // NOP instruction
val pc = Module(new Pc())
// by default setting the save pc in fetch to false.
io.csrRegFile_csr_save_if_o := false.B
io.csrRegFile_csr_if_pc_o := 0.U
io.csrRegFile_csr_save_cause_o := false.B
// IF/ID registers
val if_id_pc_reg = Reg(SInt())
val if_id_pc4_reg = Reg(SInt())
val if_id_inst_reg = RegInit(NOP)
// checking if we have an interrupt to deal with
val handle_irq = io.csrRegFile_irq_pending_i && io.csrRegFile_csr_mstatus_mie_i
// if irq then stopping the fetch for getting new instruction because we need to jump to the trap handler
val halt_if = Wire(Bool())
halt_if := Mux(handle_irq, true.B, false.B)
// initializing the mtvec register
io.csrRegFile_csr_mtvec_init_o := Mux(io.core_init_mtvec_i, true.B, false.B)
// csr register file default outputs
io.csrRegFile_csr_save_if_o := false.B
io.csrRegFile_csr_save_cause_o := false.B
io.csrRegFile_exc_cause_o := Exc_Cause.EXC_CAUSE_INSN_ADDR_MISA
// Send the next pc value to the instruction memory
io.core_instr_addr_o := pc.io.in(13, 0).asUInt
// if device is ready to accept the request then send a valid signal to fetch from.
io.core_instr_req_o := Mux(io.core_instr_gnt_i, true.B, false.B)
// wait for valid signal to arrive indicating the fetched instruction is valid otherwise send NOP
val instr = Mux(io.core_instr_rvalid_i, io.core_instr_rdata_i, NOP)
when(!io.core_stall_i && !halt_if) {
// send the current pc value to the Decode stage
if_id_pc_reg := pc.io.out
// send the pc + 4 to the Decode stage
if_id_pc4_reg := pc.io.pc4
}
when(!io.core_stall_i && !halt_if) {
when(io.decode_hazardDetection_inst_forward_i === 1.U) {
if_id_inst_reg := io.decode_hazardDetection_inst_i
if_id_pc_reg := io.decode_hazardDetection_current_pc_i
}.otherwise {
// instead of sending the instruction data directly to the decode first see if
// the reset has been low for one cycle with the `started` val. If `started` is
// high it means the reset has not been low for one clock cycle so still send
// NOP instruction to the Decode otherwise send the received data from the ICCM.
// inst_reg := Mux(started, NOP, io.instr_rdata_i)
if_id_inst_reg := instr
}
}
// Stopping the pc from updating since the pipeline has to be stalled. When the instruction is 0 and the next pc select
// is also 0 we have a condition where the PC needs to be stopped for UART. Used next pc select because there is
// a condition where the instruction is 0 but next pc select has some value for JALR instruction so the pc will not
// get updated.
// when(io.inst_in === 0.U && io.ctrl_next_pc_sel === 0.U) {
// pc.io.in := pc.io.out
// //pc.io.stall := 1.U
// } .otherwise {
when(!io.core_stall_i && !halt_if) {
when(io.decode_hazardDetection_pc_forward_i === 1.U) {
pc.io.in := io.decode_hazardDetection_pc_i
}.otherwise {
when(io.decode_ctrl_next_pc_sel_i === "b01".U) {
when(io.decode_branchLogic_output_i === 1.U && io.decode_ctrl_out_branch_i === 1.U) {
pc.io.in := io.decode_sb_imm_i
if_id_pc_reg := 0.S
if_id_pc4_reg := 0.S
if_id_inst_reg := NOP
}.otherwise {
pc.io.in := pc.io.pc4
}
}.elsewhen(io.decode_ctrl_next_pc_sel_i === "b10".U) {
pc.io.in := io.decode_uj_imm_i
if_id_pc_reg := 0.S
if_id_pc4_reg := 0.S
if_id_inst_reg := NOP
}.elsewhen(io.decode_ctrl_next_pc_sel_i === "b11".U) {
pc.io.in := io.decode_jalr_imm_i
if_id_pc_reg := 0.S
if_id_pc4_reg := 0.S
if_id_inst_reg := NOP
}.elsewhen(io.decode_mret_inst_i) {
pc.io.in := io.csrRegFile_csr_mepc_i.asSInt()
if_id_pc_reg := 0.S
if_id_pc4_reg := 0.S
if_id_inst_reg := NOP
}.otherwise {
pc.io.in := pc.io.pc4
}
}
}.elsewhen(!io.core_stall_i && halt_if) {
pc.io.in := Cat(io.csrRegFile_csr_mtvec_i(31, 8), 0.U(1.W), Exc_Cause.EXC_CAUSE_IRQ_EXTERNAL_M(4, 0), 0.U(2.W)).asSInt()
if_id_inst_reg := NOP // when halted pass NOP since we dont want to repeatedly send the current instruction as it will be executed twice
io.csrRegFile_csr_save_if_o := true.B
// Checking which pc to set in mepc. If the pc in had a branch instruction when interrupt came
// then save the calculated branch addres in mepc to return back to correct instruction after mret
// otherwise save pc's current value in mepc.
io.csrRegFile_csr_if_pc_o := Mux(io.decode_ctrl_next_pc_sel_i === "b01".U, io.decode_sb_imm_i.asUInt(),
Mux(io.decode_ctrl_next_pc_sel_i === "b10".U, io.decode_uj_imm_i.asUInt(),
Mux(io.decode_ctrl_next_pc_sel_i === "b11".U, io.decode_jalr_imm_i.asUInt(), pc.io.out.asUInt())))
io.csrRegFile_csr_save_cause_o := true.B
io.csrRegFile_exc_cause_o := Exc_Cause.EXC_CAUSE_IRQ_EXTERNAL_M
}
.otherwise {
pc.io.in := pc.io.out
}
io.decode_if_id_pc_o := if_id_pc_reg
io.decode_if_id_pc4_o := if_id_pc4_reg
io.decode_if_id_inst_o := if_id_inst_reg
}