Files
fmn_processor/src/main/scala/projet/ControlUnit.scala

226 lines
6.0 KiB
Scala
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package projet
import chisel3._
import chisel3.util.switch
import chisel3.util.is
import projet.op.OpImm
import projet.op.OpR
import projet.op.OpBranch
import projet.op.OpStore
import projet.op.OpLoad
import projet.op.OpImmW
class CUInterface extends Bundle {
val instruction = Input(UInt(32.W))
val reg_file_we = Output(Bool())
val alu_opcode = Output(AluOpCode())
// TODO: Maybe bundle alu <> cu
// Alu comparison result
val alu_comp_result = Input(Bool())
val alu_word_mode = Output(Bool())
val optype = Output(OpType())
// True if the decoded instruction is a jump
val is_jump = Output(Bool())
// DMem connections
val memory_size = Output(DMemSize())
val memory_en = Output(Bool())
val memory_we = Output(Bool())
val memory_sign_extend = Output(
Bool()
) // Wether to signe extend the output of the memory for bytes, half loads
// Muxers
// The naming convention is as follows : mux_xxx_yyy.
// If the signal is hot, xxx is selected otherwise yyy is selected
// Sends alu or immediate to write back
val mux_alu_imm = Output(Bool())
// Selects regA or pc for alu a
val mux_rega_pc = Output(Bool())
// Selects regB or immediate for alu b
val mux_regb_imm = Output(Bool())
// Selects 4 or immediate for pc incrementation
val mux_incrpc4_imm = Output(Bool())
// Selects pc or previous pc for pc incrementation
val mux_regpc_executepc = Output(Bool())
// Selects pc adder or write back for pc write
val mux_pcadder_jalrwriteback = Output(Bool())
// Selects pc or write back for register write
val mux_writeback_pc = Output(Bool())
// Selects aluout or memory data out for writeback_line
val mux_executeout_dout = Output(Bool())
}
object OpType extends ChiselEnum {
val U, I, J, B, S = Value
// Type IR is not defined in the RiscV specification
// but the immediate needs to be handled differently
// since the 31st bit indicates wether it is an
// arithmetic or logical shift
val IR = Value
}
object OpCode extends ChiselEnum {
// Type U
val LUI = "b0110111".U
val AUIPC = "b0010111".U
// Type I + Type IR
// Instruction format
// xxx rd, rs1, imm
// Perfomrs some operation with rs1 and immediate
// and writes back to a register
// addi, andi, ori, xori, slli, srli, srai,
// slti, sltiu
val OpImm = "b0010011".U
// Instruction format
// xxx rd, rs1, rs2
// Perfomrs some operation with rs1 and rd2
// and writes back to a register
// add, and, or, xor, sll, srl, sra, slt, stlu, mul, mulh, mulhsu, mulhu, div, divu, rem, remu
val OpR = "b0110011".U;
// Type J
val JAL = "b1101111".U
// Type I
val JALR = "b1100111".U
// Type B
val OpBranch = "b1100011".U
// Type S
val OpStore = "b0100011".U
// Type I
val OpLoad = "b0000011".U
// ~~ Rv64i ~~
val OpImmW = "b0011011".U
// TypeR
val OpRW = "b0111011".U
}
class ControlUnit() extends Module {
val io = IO(new CUInterface())
io.reg_file_we := false.B
io.alu_opcode := AluOpCode.Add
io.alu_word_mode := false.B
io.optype := OpType.U
io.is_jump := false.B;
io.memory_size := DMemSize.Word
io.memory_en := false.B
io.memory_we := false.B
io.memory_sign_extend := false.B;
io.mux_alu_imm := true.B;
io.mux_rega_pc := true.B;
io.mux_regb_imm := true.B;
io.mux_incrpc4_imm := true.B;
io.mux_regpc_executepc := true.B;
io.mux_writeback_pc := true.B;
io.mux_pcadder_jalrwriteback := true.B;
io.mux_executeout_dout := true.B;
// Decode instruction
val opcode = io.instruction(6, 0);
val funct3 = io.instruction(14, 12);
val funct7 = io.instruction(31, 25);
switch(opcode) {
// ~~~ Single instruction OpCodes ~~
// ~ U instructions ~
is(OpCode.LUI) {
io.reg_file_we := true.B // Write to regfile
io.mux_alu_imm := false.B // Send immy directly to refile
io.optype := OpType.U
}
is(OpCode.AUIPC) {
io.alu_opcode := AluOpCode.Add
io.reg_file_we := true.B // Write to regfile
io.mux_rega_pc := false.B // Send PC to ALU A
io.mux_regb_imm := false.B; // Send immu to ALU B
io.optype := OpType.U
}
// ~ J instructions ~
is(OpCode.JAL) {
io.alu_opcode := AluOpCode.Add // ALU is unused
io.reg_file_we := true.B // Write to regfile
io.mux_writeback_pc := false.B;
// io.mux_rega_pc := false.B // Send PC to ALU A
// io.mux_regb_imm := false.B; // Send imm to ALU B
io.is_jump := true.B
io.mux_incrpc4_imm := false.B; // Send the immediate in PC
io.mux_regpc_executepc := false.B; // Add the immediate to the previous PC
io.mux_pcadder_jalrwriteback := true.B;
io.optype := OpType.J
}
is(OpCode.JALR) {
io.alu_opcode := AluOpCode.Add
io.reg_file_we := true.B // Write to regfile
io.mux_writeback_pc := false.B // Write next instruction PC to rd
io.is_jump := true.B // Insert no-op to discard fetched next instruction
io.mux_rega_pc := true.B // Send rs1 to ALU A
io.mux_regb_imm := false.B; // Send imm to ALU B
io.mux_alu_imm := true.B; // Send alu out to write back line
io.mux_pcadder_jalrwriteback := false.B; // Set pc to writeback dest
io.optype := OpType.I
}
is(OpCode.OpImm) {
OpImm.opImm(io)
}
is(OpCode.OpR) {
OpR.opR(io);
}
is(OpCode.OpBranch) {
OpBranch.opBranch(io);
}
is(OpCode.OpStore) {
OpStore.opStore(io);
}
is(OpCode.OpLoad) {
OpLoad.opLoad(io);
}
is(OpCode.OpImmW) {
OpImmW.opImmW(io);
}
is(OpCode.OpRW) {
io.alu_word_mode := true.B
OpR.opR(io);
}
}
}