blob: eef15b154f3f1e156cbd3ede385253a15bd2af73 [file] [log] [blame]
package components
import chisel3._
import chisel3.util._
import chisel3.experimental.ChiselEnum
object ALUOp extends ChiselEnum {
val ADD, AND, NOT, OR, SLL, SLT, SRA, SRL, SUB, XOR = Value
}
class ZCNV extends Bundle {
val z = Bool()
val c = Bool()
val n = Bool()
val v = Bool()
}
class ALU extends Module {
val io = IO(new Bundle {
val in1 = Input(UInt(16.W))
val in2 = Input(UInt(16.W))
val op = Input(ALUOp())
val out = Output(UInt(16.W))
val cc = Output(new ZCNV)
})
val in1 = Wire(UInt(17.W))
val in2 = Wire(UInt(17.W))
in1 := io.in1
in2 := io.in2
val result = Wire(UInt(17.W))
io.out := result(15, 0)
val in1_minus_in2 = Wire(UInt(17.W))
in1_minus_in2 := in1 - in2
result := 0.U
// Compute result
switch (io.op) {
is (ALUOp.ADD) { result := in1 + in2 }
is (ALUOp.AND) { result := in1 & in2 }
is (ALUOp.NOT) { result := ~in1 }
is (ALUOp.OR) { result := in1 | in2 }
is (ALUOp.SLL) { result := in1 << in2(3, 0) }
is (ALUOp.SLT) { result := Cat(0.U(15.W), (in1(15, 0).asSInt() < in2(15, 0).asSInt())(0)) }
is (ALUOp.SRA) { result := (in1(15, 0).asSInt() >> in2(3, 0)).asUInt()(15,0) }
is (ALUOp.SRL) { result := in1 >> in2(3, 0) }
is (ALUOp.SUB) { result := in1_minus_in2 }
is (ALUOp.XOR) { result := in1 ^ in2 }
}
// Compute flags
when (io.op === ALUOp.ADD) {
io.cc.z := (io.out === 0.U)
io.cc.c := result(16)
io.cc.n := result(15)
io.cc.v := (in1(15) && in2(15) && !io.out(15)) ||
(!in1(15) && !in2(15) && io.out(15))
}
.elsewhen (io.op === ALUOp.SUB) {
io.cc.z := (io.out === 0.U)
io.cc.c := (in2 >= in1) // Weird but works
io.cc.n := result(15)
io.cc.v := (in1(15) && !in2(15) && !io.out(15)) ||
(!in1(15) && in2(15) && io.out(15))
}
.elsewhen (io.op === ALUOp.SLT) {
io.cc.z := (in1_minus_in2 === 0.U)
io.cc.c := (in2 >= in1)
io.cc.n := in1_minus_in2(15)
io.cc.v := (in1(15) && !in2(15) && !in1_minus_in2(15)) ||
(!in1(15) && in2(15) && in1_minus_in2(15))
}
.otherwise {
io.cc.z := (io.out === 0.U)
io.cc.c := false.B
io.cc.n := result(15)
io.cc.v := false.B
}
}