blob: 3ce227d0d5b48ab1636e4594a67b3acb0994a2bc [file] [log] [blame]
// Copyright 2023 Google LLC
package kelvin
import chisel3._
import chisel3.util._
import common._
object Alu {
def apply(p: Parameters): Alu = {
return Module(new Alu(p))
}
}
case class AluOp() {
val ADD = 0
val SUB = 1
val SLT = 2
val SLTU = 3
val XOR = 4
val OR = 5
val AND = 6
val SLL = 7
val SRL = 8
val SRA = 9
val LUI = 10
val CLZ = 11
val CTZ = 12
val PCNT = 13
val MIN = 14
val MINU = 15
val MAX = 16
val MAXU = 17
val Entries = 18
}
class AluIO(p: Parameters) extends Bundle {
val valid = Input(Bool())
val addr = Input(UInt(5.W))
val op = Input(UInt(new AluOp().Entries.W))
}
class Alu(p: Parameters) extends Module {
val io = IO(new Bundle {
// Decode cycle.
val req = new AluIO(p)
// Execute cycle.
val rs1 = Flipped(new RegfileReadDataIO)
val rs2 = Flipped(new RegfileReadDataIO)
val rd = Flipped(new RegfileWriteDataIO)
})
val alu = new AluOp()
val valid = RegInit(false.B)
val addr = Reg(UInt(5.W))
val op = RegInit(0.U(alu.Entries.W))
// Pulse the cycle after the decoded request.
valid := io.req.valid
// Avoid output toggles by not updating state between uses.
// The Regfile has the same behavior, leaving read ports unchanged.
when (io.req.valid) {
addr := io.req.addr
op := io.req.op
}
// val rs1 = MuxOR(valid, io.rs1.data)
// val rs2 = MuxOR(valid, io.rs2.data)
val rs1 = io.rs1.data
val rs2 = io.rs2.data
val shamt = rs2(4,0)
// TODO: should we be masking like this for energy?
// TODO: a single addsub for add/sub/slt/sltu
// val add = MuxOR(op(alu.ADD), rs1) + MuxOR(op(alu.ADD), rs2)
// val sub = MuxOR(op(alu.SUB), rs1) - MuxOR(op(alu.SUB), rs2)
// val sll = MuxOR(op(alu.SLL), rs1) << MuxOR(op(alu.SLL), shamt)
// val srl = MuxOR(op(alu.SRL), rs1) >> MuxOR(op(alu.SRL), shamt)
// val sra = (MuxOR(op(alu.SRA), rs1.asSInt, 0.S) >> MuxOR(op(alu.SRA), shamt)).asUInt
// val slt = MuxOR(op(alu.SLT), rs1.asSInt, 0.S) < MuxOR(op(alu.SLT), rs2.asSInt, 0.S)
// val sltu = MuxOR(op(alu.SLTU), rs1) < MuxOR(op(alu.SLTU), rs2)
// val and = MuxOR(op(alu.AND), rs1) & MuxOR(op(alu.AND), rs2)
// val or = MuxOR(op(alu.OR), rs1) | MuxOR(op(alu.OR), rs2)
// val xor = MuxOR(op(alu.XOR), rs1) ^ MuxOR(op(alu.XOR), rs2)
// val lui = MuxOR(op(alu.LUI), rs2)
// val clz = MuxOR(op(alu.CLZ), CLZ(rs1))
// val ctz = MuxOR(op(alu.CTZ), CTZ(rs1))
// val pcnt = MuxOR(op(alu.PCNT), PopCount(rs1))
// io.rd.data := add | sub | sll | srl | sra | slt | sltu | and | or | xor | lui
io.rd.valid := valid
io.rd.addr := addr
io.rd.data := MuxOR(op(alu.ADD), rs1 + rs2) |
MuxOR(op(alu.SUB), rs1 - rs2) |
MuxOR(op(alu.SLT), rs1.asSInt < rs2.asSInt) |
MuxOR(op(alu.SLTU), rs1 < rs2) |
MuxOR(op(alu.XOR), rs1 ^ rs2) |
MuxOR(op(alu.OR), rs1 | rs2) |
MuxOR(op(alu.AND), rs1 & rs2) |
MuxOR(op(alu.SLL), rs1 << shamt) |
MuxOR(op(alu.SRL), rs1 >> shamt) |
MuxOR(op(alu.SRA), (rs1.asSInt >> shamt).asUInt) |
MuxOR(op(alu.LUI), rs2) |
MuxOR(op(alu.CLZ), Clz(rs1)) |
MuxOR(op(alu.CTZ), Ctz(rs1)) |
MuxOR(op(alu.PCNT), PopCount(rs1)) |
MuxOR(op(alu.MIN), Mux(rs1.asSInt < rs2.asSInt, rs1, rs2)) |
MuxOR(op(alu.MAX), Mux(rs1.asSInt > rs2.asSInt, rs1, rs2)) |
MuxOR(op(alu.MINU), Mux(rs1 < rs2, rs1, rs2)) |
MuxOR(op(alu.MAXU), Mux(rs1 > rs2, rs1, rs2))
// Assertions.
assert(!(valid && !io.rs1.valid && !op(alu.LUI)))
assert(!(valid && !io.rs2.valid))
}