226 lines
6.0 KiB
Scala
226 lines
6.0 KiB
Scala
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);
|
||
}
|
||
}
|
||
}
|