| // Copyright 2023 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| 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 = io.rs1.data |
| val rs2 = io.rs2.data |
| val shamt = rs2(4,0) |
| |
| 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)) |
| } |