276 lines
7.4 KiB
Scala
276 lines
7.4 KiB
Scala
package projet
|
|
|
|
import chisel3._
|
|
import chisel3.util.switch
|
|
import chisel3.util.is
|
|
|
|
object AluOpCode extends ChiselEnum {
|
|
val Add, Sub, Mul, Mulh, Mulhsu, Mulhu, Div, Divu, Rem, Remu, And, Or, Xor,
|
|
ShiftLeft, ShiftRight, ShiftArithmeticRight, LessThanSigned,
|
|
LessThanUnsigned, GreaterEqualSigned, GreaterEqualUnsigned, Equal =
|
|
Value
|
|
}
|
|
|
|
class Alu extends Module {
|
|
import AluOpCode._
|
|
|
|
val io = IO(new Bundle {
|
|
val a = Input(UInt(64.W))
|
|
val b = Input(UInt(64.W))
|
|
val out = Output(UInt(64.W))
|
|
val opcode = Input(AluOpCode())
|
|
val comp_result = Output(Bool())
|
|
|
|
// Should stop the stall for the current computation (e.g. Division)
|
|
val should_stop_stall = Output(Bool())
|
|
|
|
// ~~ Rv64i ~~
|
|
// If word_mode is enabled, operations are performed
|
|
// on 32-bit-truncated inputs and then sign extended to 64bits
|
|
val word_mode = Input(Bool())
|
|
})
|
|
|
|
io.should_stop_stall := false.B
|
|
io.out := 0.U;
|
|
io.comp_result := false.B;
|
|
val out = WireInit(0.U(64.W))
|
|
val op_a = WireInit(0.U(64.W))
|
|
val op_b = WireInit(0.U(64.W))
|
|
|
|
// Defaults
|
|
op_a := io.a
|
|
op_b := io.b
|
|
val op_a_sign = WireInit(op_a(63))
|
|
val op_b_sign = WireInit(op_b(63))
|
|
val op_a_unsigned = WireInit(op_a)
|
|
val op_b_unsigned = WireInit(op_b)
|
|
io.out := out
|
|
|
|
// Truncate operands, sext result
|
|
when(io.word_mode) {
|
|
op_a := io.a(31, 0)
|
|
op_b := io.b(31, 0)
|
|
op_a_sign := op_a(31)
|
|
op_b_sign := op_b(31)
|
|
|
|
io.out := SignExtend.Sext(out(31, 0), 64)
|
|
}
|
|
|
|
when(op_a_sign) {
|
|
op_a_unsigned := Utils.two_complement(op_a, io.word_mode)
|
|
}
|
|
when(op_b_sign) {
|
|
op_b_unsigned := Utils.two_complement(op_b, io.word_mode)
|
|
}
|
|
|
|
val in_computation = RegInit(false.B)
|
|
|
|
// // Division
|
|
// val divider = Module(new Divider(64, Constants.DIVISION_CYCLES_COUNT))
|
|
// divider.io.word_mode := io.word_mode
|
|
// divider.io.dividend := op_a_unsigned
|
|
// divider.io.divisor := op_b_unsigned
|
|
// divider.io.start := false.B
|
|
// def div_by_zero() = {
|
|
// when(io.word_mode) {
|
|
// out := (-1).S(32.W).asUInt
|
|
// }.otherwise {
|
|
// out := (-1).S(64.W).asUInt
|
|
// }
|
|
// }
|
|
|
|
// Multiplication
|
|
val multiplication_res = op_a * op_b // Mul non signée
|
|
val multiplication_low =
|
|
Mux(io.word_mode, multiplication_res(31, 0), multiplication_res(63, 0))
|
|
val multiplication_high =
|
|
Mux(
|
|
io.word_mode,
|
|
multiplication_res(63, 32),
|
|
multiplication_res(127, 64)
|
|
)
|
|
|
|
switch(io.opcode) {
|
|
is(Add) {
|
|
out := op_a + op_b;
|
|
}
|
|
|
|
is(Sub) {
|
|
out := op_a - op_b;
|
|
}
|
|
|
|
is(Mul) {
|
|
out := multiplication_low;
|
|
}
|
|
|
|
is(Mulh) {
|
|
val correction =
|
|
Mux(op_a_sign, op_b, 0.U) + Mux(op_b_sign, op_a, 0.U)
|
|
val multiplication_res_with_correction =
|
|
multiplication_high - correction
|
|
out := multiplication_res_with_correction;
|
|
}
|
|
|
|
is(Mulhsu) {
|
|
val correction =
|
|
Mux(op_a_sign, op_b, 0.U)
|
|
val multiplication_res_with_correction =
|
|
multiplication_high - correction
|
|
out := multiplication_res_with_correction;
|
|
}
|
|
|
|
is(Mulhu) {
|
|
out := multiplication_high;
|
|
}
|
|
|
|
// is(Div) {
|
|
// when(op_b === 0.U) {
|
|
// div_by_zero()
|
|
// }.elsewhen(op_a_sign ^ op_b_sign) {
|
|
// out := Utils.two_complement(divider.io.quotient, io.word_mode)
|
|
// }.otherwise {
|
|
// out := divider.io.quotient
|
|
// }
|
|
// }
|
|
//
|
|
// is(Divu) {
|
|
// divider.io.dividend := op_a
|
|
// divider.io.divisor := op_b
|
|
// when(op_b === 0.U) {
|
|
// div_by_zero()
|
|
// }.otherwise { out := divider.io.quotient; }
|
|
// }
|
|
//
|
|
// is(Rem) {
|
|
// when(op_b === 0.U) {
|
|
// out := op_a
|
|
// }.elsewhen(
|
|
// op_a_sign && !op_b_sign && divider.io.remainder =/= 0.U
|
|
// ) {
|
|
// out := op_b - divider.io.remainder
|
|
// }.elsewhen(
|
|
// !op_a_sign && op_b_sign && divider.io.remainder =/= 0.U
|
|
// ) {
|
|
// out := Utils.two_complement(
|
|
// Utils.two_complement(op_b) - divider.io.remainder,
|
|
// io.word_mode
|
|
// )
|
|
// }.elsewhen(op_a_sign && op_b_sign) {
|
|
// out := Utils.two_complement(divider.io.remainder, io.word_mode)
|
|
// }.otherwise {
|
|
// out := divider.io.remainder
|
|
// }
|
|
// }
|
|
//
|
|
// is(Remu) {
|
|
// divider.io.dividend := op_a
|
|
// divider.io.divisor := op_b
|
|
// when(op_b === 0.U) {
|
|
// out := op_a
|
|
// }.otherwise {
|
|
// out := divider.io.remainder
|
|
// }
|
|
// }
|
|
|
|
is(And) {
|
|
out := op_a & op_b;
|
|
}
|
|
|
|
is(Or) {
|
|
out := op_a | op_b;
|
|
}
|
|
|
|
is(Xor) {
|
|
out := op_a ^ op_b;
|
|
}
|
|
|
|
is(ShiftLeft) {
|
|
out := op_a << op_b(5, 0);
|
|
}
|
|
|
|
is(ShiftRight) {
|
|
out := op_a >> op_b(5, 0);
|
|
}
|
|
|
|
is(ShiftArithmeticRight) {
|
|
// >> means arithmetic shift for SInts
|
|
out := (op_a.asSInt >> op_b(5, 0)).asUInt;
|
|
// Signed shift on 32bit requires careful handling
|
|
when(io.word_mode) {
|
|
|
|
out := (op_a(31, 0).asSInt >> op_b(5, 0)).asUInt
|
|
}
|
|
}
|
|
|
|
is(LessThanUnsigned) {
|
|
val less_than = op_a < op_b;
|
|
out := less_than;
|
|
io.comp_result := less_than;
|
|
}
|
|
|
|
is(LessThanSigned) {
|
|
val less_than = op_a.asSInt < op_b.asSInt
|
|
out := less_than
|
|
io.comp_result := less_than;
|
|
}
|
|
|
|
is(GreaterEqualUnsigned) {
|
|
val geq_than = op_a >= op_b;
|
|
out := geq_than
|
|
io.comp_result := geq_than;
|
|
}
|
|
|
|
is(GreaterEqualSigned) {
|
|
val geq_than = op_a.asSInt >= op_b.asSInt
|
|
out := geq_than
|
|
io.comp_result := geq_than;
|
|
}
|
|
|
|
is(Equal) {
|
|
io.comp_result := op_a === op_b;
|
|
}
|
|
}
|
|
|
|
// switch(io.opcode) {
|
|
// is(Div, Divu, Rem, Remu) {
|
|
// when(!in_computation) {
|
|
// divider.io.start := true.B
|
|
// in_computation := true.B
|
|
// }.elsewhen(divider.io.ready) {
|
|
// io.should_stop_stall := true.B
|
|
// in_computation := false.B
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
|
|
// Special overflow cases for Div and Rem
|
|
when(
|
|
io.word_mode &&
|
|
op_b === ((BigInt(1) << 32) - 1).U(32.W) &&
|
|
op_a === (-1).S(32.W).asUInt
|
|
) {
|
|
switch(io.opcode) {
|
|
is(Div) {
|
|
out := (1.U << 31)
|
|
}
|
|
is(Rem) {
|
|
out := 0.U
|
|
}
|
|
}
|
|
}.elsewhen(
|
|
!io.word_mode &&
|
|
op_b === ((BigInt(1) << 64) - 1).U(64.W) &&
|
|
op_a === (-1).S(64.W).asUInt
|
|
) {
|
|
switch(io.opcode) {
|
|
is(Div) {
|
|
out := (1.U << 63)
|
|
}
|
|
is(Rem) {
|
|
out := 0.U
|
|
}
|
|
}
|
|
}
|
|
}
|