| // 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. |
| |
| |
| // Decode: Contains decode logic to be forwarded to the appropriate functional |
| // block. A serialization mechanism is introduced to stall a decoded instruction |
| // from bring presented to the functional block until next cycle if the block has |
| // already been presented with an instruction from another decoder. |
| |
| package kelvin |
| |
| import chisel3._ |
| import chisel3.util._ |
| import common._ |
| |
| object Decode { |
| def apply(p: Parameters, pipeline: Int): Decode = { |
| return Module(new Decode(p, pipeline)) |
| } |
| } |
| |
| class DecodeSerializeIO extends Bundle { |
| val lsu = Output(Bool()) |
| val mul = Output(Bool()) |
| val jump = Output(Bool()) |
| val brcond = Output(Bool()) |
| val vinst = Output(Bool()) // all vector instructions |
| |
| def defaults() = { |
| lsu := false.B |
| mul := false.B |
| jump := false.B |
| brcond := false.B |
| vinst := false.B |
| } |
| } |
| |
| class DecodedInstruction extends Bundle { |
| // Immediates |
| val imm12 = UInt(32.W) |
| val imm20 = UInt(32.W) |
| val immjal = UInt(32.W) |
| val immbr = UInt(32.W) |
| val immcsr = UInt(32.W) |
| val immst = UInt(32.W) |
| |
| // RV32I |
| val lui = Bool() |
| val auipc = Bool() |
| val jal = Bool() |
| val jalr = Bool() |
| val beq = Bool() |
| val bne = Bool() |
| val blt = Bool() |
| val bge = Bool() |
| val bltu = Bool() |
| val bgeu = Bool() |
| val csrrw = Bool() |
| val csrrs = Bool() |
| val csrrc = Bool() |
| val lb = Bool() |
| val lh = Bool() |
| val lw = Bool() |
| val lbu = Bool() |
| val lhu = Bool() |
| val sb = Bool() |
| val sh = Bool() |
| val sw = Bool() |
| val fence = Bool() |
| val addi = Bool() |
| val slti = Bool() |
| val sltiu = Bool() |
| val xori = Bool() |
| val ori = Bool() |
| val andi = Bool() |
| val slli = Bool() |
| val srli = Bool() |
| val srai = Bool() |
| val add = Bool() |
| val sub = Bool() |
| val slt = Bool() |
| val sltu = Bool() |
| val xor = Bool() |
| val or = Bool() |
| val and = Bool() |
| val sll = Bool() |
| val srl = Bool() |
| val sra = Bool() |
| |
| // RV32M |
| val mul = Bool() |
| val mulh = Bool() |
| val mulhsu = Bool() |
| val mulhu = Bool() |
| val mulhr = Bool() |
| val mulhsur = Bool() |
| val mulhur = Bool() |
| val dmulh = Bool() |
| val dmulhr = Bool() |
| val div = Bool() |
| val divu = Bool() |
| val rem = Bool() |
| val remu = Bool() |
| |
| // RV32B |
| val clz = Bool() |
| val ctz = Bool() |
| val pcnt = Bool() |
| val min = Bool() |
| val minu = Bool() |
| val max = Bool() |
| val maxu = Bool() |
| |
| // Vector instructions. |
| val getvl = Bool() |
| val getmaxvl = Bool() |
| val vld = Bool() |
| val vst = Bool() |
| val viop = Bool() |
| |
| // Core controls. |
| val ebreak = Bool() |
| val ecall = Bool() |
| val eexit = Bool() |
| val eyield = Bool() |
| val ectxsw = Bool() |
| val mpause = Bool() |
| val mret = Bool() |
| val undef = Bool() |
| |
| // Fences. |
| val fencei = Bool() |
| val flushat = Bool() |
| val flushall = Bool() |
| |
| // Scalar logging. |
| val slog = Bool() |
| |
| def isAluImm(): Bool = { |
| addi || slti || sltiu || xori || ori || andi || slli || srli || srai |
| } |
| def isAluReg(): Bool = { |
| add || sub || slt || sltu || xor || or || and || sll || srl || sra |
| } |
| def isAlu1Bit(): Bool = { clz || ctz || pcnt } |
| def isAlu2Bit(): Bool = { min || minu || max || maxu } |
| def isCsr(): Bool = { csrrw || csrrs || csrrc } |
| def isCondBr(): Bool = { beq || bne || blt || bge || bltu || bgeu } |
| def isLoad(): Bool = { lb || lh || lw || lbu || lhu } |
| def isStore(): Bool = { sb || sh || sw } |
| def isLsu(): Bool = { isLoad() || isStore() || vld || vst || flushat || flushall } |
| def isMul(): Bool = { mul || mulh || mulhsu || mulhu || mulhr || mulhsur || mulhur || dmulh || dmulhr } |
| def isDvu(): Bool = { div || divu || rem || remu } |
| def isVector(): Bool = { vld || vst || viop || getvl || getmaxvl } |
| } |
| |
| class Decode(p: Parameters, pipeline: Int) extends Module { |
| val io = IO(new Bundle { |
| // Core controls. |
| val halted = Input(Bool()) |
| |
| // Decode input interface. |
| val inst = Flipped(new FetchInstruction(p)) |
| val scoreboard = new Bundle { |
| val regd = Input(UInt(32.W)) |
| val comb = Input(UInt(32.W)) |
| val spec = Output(UInt(32.W)) |
| } |
| val mactive = Input(Bool()) // memory active |
| |
| // Register file decode cycle interface. |
| val rs1Read = Flipped(new RegfileReadAddrIO) |
| val rs1Set = Flipped(new RegfileReadSetIO) |
| val rs2Read = Flipped(new RegfileReadAddrIO) |
| val rs2Set = Flipped(new RegfileReadSetIO) |
| val rdMark = Flipped(new RegfileWriteAddrIO) |
| val busRead = Flipped(new RegfileBusAddrIO) |
| |
| // ALU interface. |
| val alu = Valid(new AluCmd) |
| |
| // Branch interface. |
| val bru = Flipped(new BruIO(p)) |
| |
| // CSR interface. |
| val csr = Valid(new CsrCmd) |
| |
| // LSU interface. |
| val lsu = Decoupled(new LsuCmd) |
| |
| // Multiplier interface. |
| val mlu = Valid(new MluCmd) |
| |
| // Divide interface. |
| val dvu = Decoupled(new DvuCmd) |
| |
| // Vector interface. |
| val vinst = if (p.enableVector) { |
| Some(Decoupled(new VInstCmd)) |
| } else { None } |
| |
| // Branch status. |
| val branchTaken = Input(Bool()) |
| |
| // Interlock Controls |
| val interlock = Input(Bool()) |
| val serializeIn = Flipped(new DecodeSerializeIO) |
| val serializeOut = new DecodeSerializeIO |
| |
| // Scalar logging. |
| val slog = Output(Bool()) |
| }) |
| |
| val decodeEn = io.inst.valid && io.inst.ready && !io.branchTaken |
| |
| // The decode logic. |
| val d = DecodeInstruction(p, pipeline, io.inst.addr, io.inst.inst) |
| |
| val vldst = d.vld || d.vst |
| val vldst_wb = vldst && io.inst.inst(28) |
| |
| val rdAddr = Mux(vldst, io.inst.inst(19,15), io.inst.inst(11,7)) |
| val rs1Addr = io.inst.inst(19,15) |
| val rs2Addr = io.inst.inst(24,20) |
| val rs3Addr = io.inst.inst(31,27) |
| |
| val isCsrImm = d.isCsr() && io.inst.inst(14) |
| val isCsrReg = d.isCsr() && !io.inst.inst(14) |
| |
| val isVIop = if (p.enableVector) { |
| io.vinst.get.bits.op === VInstOp.VIOP |
| } else { false.B } |
| |
| val isVIopVs1 = isVIop |
| val isVIopVs2 = isVIop && io.inst.inst(1,0) === 0.U // exclude: .vv |
| val isVIopVs3 = isVIop && io.inst.inst(2,0) === 1.U // exclude: .vvv |
| |
| // Use the forwarded scoreboard to interlock on multicycle operations. |
| val aluRdEn = !io.scoreboard.comb(rdAddr) || isVIopVs1 || d.isStore() || d.isCondBr() |
| val aluRs1En = !io.scoreboard.comb(rs1Addr) || isVIopVs1 || d.isLsu() || d.auipc |
| val aluRs2En = !io.scoreboard.comb(rs2Addr) || isVIopVs2 || d.isLsu() || d.auipc || d.isAluImm() || d.isAlu1Bit() |
| // val aluRs3En = !io.scoreboard.comb(rs3Addr) || isVIopVs3 |
| // val aluEn = aluRdEn && aluRs1En && aluRs2En && aluRs3En // TODO: is aluRs3En needed? |
| val aluEn = aluRdEn && aluRs1En && aluRs2En |
| |
| // Interlock jalr but special case return. |
| val bruEn = !d.jalr || !io.scoreboard.regd(rs1Addr) || |
| io.inst.inst(31,20) === 0.U |
| |
| // Require interlock on address generation as there is no write forwarding. |
| val lsuEn = !d.isLsu() || |
| !io.serializeIn.lsu && io.lsu.ready && |
| (!d.isLsu() || !io.serializeIn.brcond) && // TODO: can this line be removed? |
| !(Mux(io.busRead.bypass, io.scoreboard.comb(rs1Addr), |
| io.scoreboard.regd(rs1Addr)) || |
| io.scoreboard.comb(rs2Addr) && (d.isStore() || vldst)) |
| |
| // Interlock mul, only one lane accepted. |
| val mulEn = (!d.isMul() || !io.serializeIn.mul) && !io.serializeIn.brcond |
| |
| |
| // Vector extension interlock. |
| val vinstEn = if (p.enableVector) { |
| !(io.serializeIn.vinst || isVIop && io.serializeIn.brcond) && |
| !(d.isVector() && !io.vinst.get.ready) |
| } else { false.B } |
| |
| // Fence interlock. |
| // Input mactive used passthrough, prefer to avoid registers in Decode. |
| val fenceEn = !(d.fence && io.mactive) |
| |
| // ALU opcode. |
| val alu = MuxCase(MakeValid(false.B, AluOp.ADD), Seq( |
| (d.auipc || d.addi || d.add) -> MakeValid(true.B, AluOp.ADD), |
| d.sub -> MakeValid(true.B, AluOp.SUB), |
| (d.slti || d.slt) -> MakeValid(true.B, AluOp.SLT), |
| (d.sltiu || d.sltu) -> MakeValid(true.B, AluOp.SLTU), |
| (d.xori || d.xor) -> MakeValid(true.B, AluOp.XOR), |
| (d.ori || d.or) -> MakeValid(true.B, AluOp.OR), |
| (d.andi || d.and) -> MakeValid(true.B, AluOp.AND), |
| (d.slli || d.sll) -> MakeValid(true.B, AluOp.SLL), |
| (d.srli || d.srl) -> MakeValid(true.B, AluOp.SRL), |
| (d.srai || d.sra) -> MakeValid(true.B, AluOp.SRA), |
| d.lui -> MakeValid(true.B, AluOp.LUI), |
| d.clz -> MakeValid(true.B, AluOp.CLZ), |
| d.ctz -> MakeValid(true.B, AluOp.CTZ), |
| d.pcnt -> MakeValid(true.B, AluOp.PCNT), |
| d.min -> MakeValid(true.B, AluOp.MIN), |
| d.minu -> MakeValid(true.B, AluOp.MINU), |
| d.max -> MakeValid(true.B, AluOp.MAX), |
| d.maxu -> MakeValid(true.B, AluOp.MAXU) |
| )) |
| io.alu.valid := decodeEn && alu.valid |
| io.alu.bits.addr := rdAddr |
| io.alu.bits.op := alu.bits |
| |
| // Branch conditional opcode. |
| val bru = new BruOp() |
| val bruOp = Wire(Vec(bru.Entries, Bool())) |
| val bruValid = WiredOR(io.bru.op) // used without decodeEn |
| io.bru.valid := decodeEn && bruValid |
| io.bru.fwd := io.inst.brchFwd |
| io.bru.op := bruOp.asUInt |
| io.bru.pc := io.inst.addr |
| io.bru.target := io.inst.addr + Mux(io.inst.inst(2), d.immjal, d.immbr) |
| io.bru.link := rdAddr |
| |
| bruOp(bru.JAL) := d.jal |
| bruOp(bru.JALR) := d.jalr |
| bruOp(bru.BEQ) := d.beq |
| bruOp(bru.BNE) := d.bne |
| bruOp(bru.BLT) := d.blt |
| bruOp(bru.BGE) := d.bge |
| bruOp(bru.BLTU) := d.bltu |
| bruOp(bru.BGEU) := d.bgeu |
| bruOp(bru.EBREAK) := d.ebreak |
| bruOp(bru.ECALL) := d.ecall |
| bruOp(bru.EEXIT) := d.eexit |
| bruOp(bru.EYIELD) := d.eyield |
| bruOp(bru.ECTXSW) := d.ectxsw |
| bruOp(bru.MPAUSE) := d.mpause |
| bruOp(bru.MRET) := d.mret |
| bruOp(bru.FENCEI) := d.fencei |
| bruOp(bru.UNDEF) := d.undef |
| |
| // CSR opcode. |
| val csr = MuxCase(MakeValid(false.B, CsrOp.CSRRW), Seq( |
| d.csrrw -> MakeValid(true.B, CsrOp.CSRRW), |
| d.csrrs -> MakeValid(true.B, CsrOp.CSRRS), |
| d.csrrc -> MakeValid(true.B, CsrOp.CSRRC) |
| )) |
| io.csr.valid := decodeEn && csr.valid |
| io.csr.bits.addr := rdAddr |
| io.csr.bits.index := io.inst.inst(31,20) |
| io.csr.bits.op := csr.bits |
| |
| // LSU opcode. |
| val lsu = MuxCase(MakeValid(false.B, LsuOp.LB), Seq( |
| d.lb -> MakeValid(true.B, LsuOp.LB), |
| d.lh -> MakeValid(true.B, LsuOp.LH), |
| d.lw -> MakeValid(true.B, LsuOp.LW), |
| d.lbu -> MakeValid(true.B, LsuOp.LBU), |
| d.lhu -> MakeValid(true.B, LsuOp.LHU), |
| d.sb -> MakeValid(true.B, LsuOp.SB), |
| d.sh -> MakeValid(true.B, LsuOp.SH), |
| d.sw -> MakeValid(true.B, LsuOp.SW), |
| d.fencei -> MakeValid(true.B, LsuOp.FENCEI), |
| d.flushat -> MakeValid(true.B, LsuOp.FLUSHAT), |
| d.flushall -> MakeValid(true.B, LsuOp.FLUSHALL), |
| (d.vld || d.vst) -> MakeValid(true.B, LsuOp.VLDST), |
| )) |
| io.lsu.valid := decodeEn && lsu.valid |
| io.lsu.bits.store := io.inst.inst(5) |
| io.lsu.bits.addr := rdAddr |
| io.lsu.bits.op := lsu.bits |
| |
| // MLU opcode. |
| val mlu = MuxCase(MakeValid(false.B, MluOp.MUL), Seq( |
| d.mul -> MakeValid(true.B, MluOp.MUL), |
| d.mulh -> MakeValid(true.B, MluOp.MULH), |
| d.mulhsu -> MakeValid(true.B, MluOp.MULHSU), |
| d.mulhu -> MakeValid(true.B, MluOp.MULHU), |
| d.mulhr -> MakeValid(true.B, MluOp.MULHR), |
| d.mulhsur -> MakeValid(true.B, MluOp.MULHSUR), |
| d.mulhur -> MakeValid(true.B, MluOp.MULHUR), |
| d.dmulh -> MakeValid(true.B, MluOp.DMULH), |
| d.dmulhr -> MakeValid(true.B, MluOp.DMULHR), |
| )) |
| io.mlu.valid := decodeEn && mlu.valid |
| io.mlu.bits.addr := rdAddr |
| io.mlu.bits.op := mlu.bits |
| |
| // DIV opcode. |
| val dvu = MuxCase(MakeValid(false.B, DvuOp.DIV), Seq( |
| d.div -> MakeValid(true.B, DvuOp.DIV), |
| d.divu -> MakeValid(true.B, DvuOp.DIVU), |
| d.rem -> MakeValid(true.B, DvuOp.REM), |
| d.remu -> MakeValid(true.B, DvuOp.REMU) |
| )) |
| io.dvu.valid := decodeEn && dvu.valid |
| io.dvu.bits.addr := rdAddr |
| io.dvu.bits.op := dvu.bits |
| val dvuEn = !dvu.valid || io.dvu.ready |
| |
| // Vector instructions. |
| val vinst = MuxCase(MakeValid(false.B, VInstOp.VLD), Seq( |
| d.vld -> MakeValid(true.B, VInstOp.VLD), |
| d.vst -> MakeValid(true.B, VInstOp.VST), |
| d.viop -> MakeValid(true.B, VInstOp.VIOP), |
| d.getvl -> MakeValid(true.B, VInstOp.GETVL), |
| d.getmaxvl -> MakeValid(true.B, VInstOp.GETMAXVL), |
| )) |
| if (p.enableVector) { |
| io.vinst.get.valid := decodeEn && vinst.valid |
| io.vinst.get.bits.addr := rdAddr |
| io.vinst.get.bits.inst := io.inst.inst |
| io.vinst.get.bits.op := vinst.bits |
| } |
| |
| // Scalar logging. |
| io.slog := decodeEn && d.slog |
| |
| // Register file read ports. |
| io.rs1Read.valid := decodeEn && (d.isCondBr() || d.isAluReg() || d.isAluImm() || d.isAlu1Bit() || d.isAlu2Bit() || |
| isCsrImm || isCsrReg || d.isMul() || d.isDvu() || d.slog || |
| d.getvl || d.vld || d.vst) |
| io.rs2Read.valid := decodeEn && (d.isCondBr() || d.isAluReg() || d.isAlu2Bit() || d.isStore() || |
| isCsrReg || d.isMul() || d.isDvu() || d.slog || d.getvl || |
| d.vld || d.vst || d.viop) |
| |
| // rs1 is on critical path to busPortAddr. |
| io.rs1Read.addr := Mux(io.inst.inst(0), rs1Addr, rs3Addr) |
| |
| // rs2 is used for the vector operation scalar value. |
| io.rs2Read.addr := rs2Addr |
| |
| // Register file set ports. |
| io.rs1Set.valid := decodeEn && (d.auipc || isCsrImm) |
| io.rs2Set.valid := io.rs1Set.valid || decodeEn && (d.isAluImm() || d.isAlu1Bit() || d.lui) |
| |
| io.rs1Set.value := Mux(d.isCsr, d.immcsr, io.inst.addr) // Program Counter (PC) |
| |
| io.rs2Set.value := MuxCase(d.imm12, |
| IndexedSeq((d.auipc || d.lui) -> d.imm20)) |
| |
| // Register file write address ports. We speculate without knowing the decode |
| // enable status to improve timing, and under a branch is ignored anyway. |
| val rdMark_valid = |
| alu.valid || csr.valid || mlu.valid || dvu.valid && io.dvu.ready || |
| lsu.valid && d.isLoad() || |
| d.getvl || d.getmaxvl || vldst_wb || |
| bruValid && (bruOp(bru.JAL) || bruOp(bru.JALR)) && rdAddr =/= 0.U |
| |
| // val scoreboard_spec = Mux(rdMark_valid || d.io.vst, UIntToOH(rdAddr, 32), 0.U) // TODO: why was d.io.vst included? |
| val scoreboard_spec = Mux(rdMark_valid, UIntToOH(rdAddr, 32), 0.U) |
| io.scoreboard.spec := Cat(scoreboard_spec(31,1), 0.U(1.W)) |
| |
| io.rdMark.valid := decodeEn && rdMark_valid |
| io.rdMark.addr := rdAddr |
| |
| // Register file bus address port. |
| // Pointer chasing bypass if immediate is zero. |
| // Load/Store immediate selection keys off bit5, and RET off bit6. |
| io.busRead.valid := lsu.valid |
| io.busRead.bypass := io.inst.inst(31,25) === 0.U && |
| Mux(!io.inst.inst(5) || io.inst.inst(6), io.inst.inst(24,20) === 0.U, |
| io.inst.inst(11,7) === 0.U) |
| |
| // SB,SH,SW 0100011 |
| val storeSelect = io.inst.inst(6,3) === 4.U && io.inst.inst(1,0) === 3.U |
| io.busRead.immen := !d.flushat |
| io.busRead.immed := Cat(d.imm12(31,5), |
| Mux(storeSelect, d.immst(4,0), d.imm12(4,0))) |
| |
| // Decode ready signalling to fetch. |
| // This must not factor branchTaken, which will be done directly in the |
| // fetch unit. Note above decodeEn resolves for branch for execute usage. |
| io.inst.ready := aluEn && bruEn && lsuEn && mulEn && dvuEn && vinstEn && fenceEn && |
| !io.serializeIn.jump && !io.halted && !io.interlock && |
| (pipeline.U === 0.U || !d.undef) |
| |
| // Serialize Interface. |
| // io.serializeOut.lsu := io.serializeIn.lsu || lsu.valid || vldst // vldst interlock for address generation cycle in vinst |
| // io.serializeOut.lsu := io.serializeIn.lsu || vldst // vldst interlock for address generation cycle in vinst |
| io.serializeOut.lsu := io.serializeIn.lsu |
| io.serializeOut.mul := io.serializeIn.mul || mlu.valid |
| io.serializeOut.jump := io.serializeIn.jump || d.jal || d.jalr || |
| d.ebreak || d.ecall || d.eexit || |
| d.eyield || d.ectxsw || d.mpause || d.mret |
| io.serializeOut.brcond := io.serializeIn.brcond | |
| d.beq || d.bne || d.blt || d.bge || d.bltu || d.bgeu |
| io.serializeOut.vinst := io.serializeIn.vinst |
| } |
| |
| object DecodeInstruction { |
| def apply(p: Parameters, pipeline: Int, addr: UInt, op: UInt): DecodedInstruction = { |
| val d = Wire(new DecodedInstruction) |
| |
| // Immediates |
| d.imm12 := Cat(Fill(20, op(31)), op(31,20)) |
| d.imm20 := Cat(op(31,12), 0.U(12.W)) |
| d.immjal := Cat(Fill(12, op(31)), op(19,12), op(20), op(30,21), 0.U(1.W)) |
| d.immbr := Cat(Fill(20, op(31)), op(7), op(30,25), op(11,8), 0.U(1.W)) |
| d.immcsr := op(19,15) |
| d.immst := Cat(Fill(20, op(31)), op(31,25), op(11,7)) |
| |
| // RV32I |
| d.lui := DecodeBits(op, "xxxxxxxxxxxxxxxxxxxx_xxxxx_0110111") |
| d.auipc := DecodeBits(op, "xxxxxxxxxxxxxxxxxxxx_xxxxx_0010111") |
| d.jal := DecodeBits(op, "xxxxxxxxxxxxxxxxxxxx_xxxxx_1101111") |
| d.jalr := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_000_xxxxx_1100111") |
| d.beq := DecodeBits(op, "xxxxxxx_xxxxx_xxxxx_000_xxxxx_1100011") |
| d.bne := DecodeBits(op, "xxxxxxx_xxxxx_xxxxx_001_xxxxx_1100011") |
| d.blt := DecodeBits(op, "xxxxxxx_xxxxx_xxxxx_100_xxxxx_1100011") |
| d.bge := DecodeBits(op, "xxxxxxx_xxxxx_xxxxx_101_xxxxx_1100011") |
| d.bltu := DecodeBits(op, "xxxxxxx_xxxxx_xxxxx_110_xxxxx_1100011") |
| d.bgeu := DecodeBits(op, "xxxxxxx_xxxxx_xxxxx_111_xxxxx_1100011") |
| d.csrrw := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_x01_xxxxx_1110011") |
| d.csrrs := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_x10_xxxxx_1110011") |
| d.csrrc := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_x11_xxxxx_1110011") |
| d.lb := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_000_xxxxx_0000011") |
| d.lh := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_001_xxxxx_0000011") |
| d.lw := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_010_xxxxx_0000011") |
| d.lbu := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_100_xxxxx_0000011") |
| d.lhu := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_101_xxxxx_0000011") |
| d.sb := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_000_xxxxx_0100011") |
| d.sh := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_001_xxxxx_0100011") |
| d.sw := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_010_xxxxx_0100011") |
| d.fence := DecodeBits(op, "0000_xxxx_xxxx_00000_000_00000_0001111") |
| d.addi := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_000_xxxxx_0010011") |
| d.slti := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_010_xxxxx_0010011") |
| d.sltiu := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_011_xxxxx_0010011") |
| d.xori := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_100_xxxxx_0010011") |
| d.ori := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_110_xxxxx_0010011") |
| d.andi := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_111_xxxxx_0010011") |
| d.slli := DecodeBits(op, "0000000_xxxxx_xxxxx_001_xxxxx_0010011") |
| d.srli := DecodeBits(op, "0000000_xxxxx_xxxxx_101_xxxxx_0010011") |
| d.srai := DecodeBits(op, "0100000_xxxxx_xxxxx_101_xxxxx_0010011") |
| d.add := DecodeBits(op, "0000000_xxxxx_xxxxx_000_xxxxx_0110011") |
| d.sub := DecodeBits(op, "0100000_xxxxx_xxxxx_000_xxxxx_0110011") |
| d.slt := DecodeBits(op, "0000000_xxxxx_xxxxx_010_xxxxx_0110011") |
| d.sltu := DecodeBits(op, "0000000_xxxxx_xxxxx_011_xxxxx_0110011") |
| d.xor := DecodeBits(op, "0000000_xxxxx_xxxxx_100_xxxxx_0110011") |
| d.or := DecodeBits(op, "0000000_xxxxx_xxxxx_110_xxxxx_0110011") |
| d.and := DecodeBits(op, "0000000_xxxxx_xxxxx_111_xxxxx_0110011") |
| d.sll := DecodeBits(op, "0000000_xxxxx_xxxxx_001_xxxxx_0110011") |
| d.srl := DecodeBits(op, "0000000_xxxxx_xxxxx_101_xxxxx_0110011") |
| d.sra := DecodeBits(op, "0100000_xxxxx_xxxxx_101_xxxxx_0110011") |
| |
| // RV32M |
| d.mul := DecodeBits(op, "0000_001_xxxxx_xxxxx_000_xxxxx_0110011") |
| d.mulh := DecodeBits(op, "0000_001_xxxxx_xxxxx_001_xxxxx_0110011") |
| d.mulhsu := DecodeBits(op, "0000_001_xxxxx_xxxxx_010_xxxxx_0110011") |
| d.mulhu := DecodeBits(op, "0000_001_xxxxx_xxxxx_011_xxxxx_0110011") |
| d.mulhr := DecodeBits(op, "0010_001_xxxxx_xxxxx_001_xxxxx_0110011") |
| d.mulhsur := DecodeBits(op, "0010_001_xxxxx_xxxxx_010_xxxxx_0110011") |
| d.mulhur := DecodeBits(op, "0010_001_xxxxx_xxxxx_011_xxxxx_0110011") |
| d.dmulh := DecodeBits(op, "0000_010_xxxxx_xxxxx_001_xxxxx_0110011") |
| d.dmulhr := DecodeBits(op, "0010_010_xxxxx_xxxxx_001_xxxxx_0110011") |
| d.div := DecodeBits(op, "0000_001_xxxxx_xxxxx_100_xxxxx_0110011") |
| d.divu := DecodeBits(op, "0000_001_xxxxx_xxxxx_101_xxxxx_0110011") |
| d.rem := DecodeBits(op, "0000_001_xxxxx_xxxxx_110_xxxxx_0110011") |
| d.remu := DecodeBits(op, "0000_001_xxxxx_xxxxx_111_xxxxx_0110011") |
| |
| // RV32B |
| d.clz := DecodeBits(op, "0110000_00000_xxxxx_001_xxxxx_0010011") |
| d.ctz := DecodeBits(op, "0110000_00001_xxxxx_001_xxxxx_0010011") |
| d.pcnt := DecodeBits(op, "0110000_00010_xxxxx_001_xxxxx_0010011") |
| d.min := DecodeBits(op, "0000101_xxxxx_xxxxx_100_xxxxx_0110011") |
| d.minu := DecodeBits(op, "0000101_xxxxx_xxxxx_101_xxxxx_0110011") |
| d.max := DecodeBits(op, "0000101_xxxxx_xxxxx_110_xxxxx_0110011") |
| d.maxu := DecodeBits(op, "0000101_xxxxx_xxxxx_111_xxxxx_0110011") |
| |
| // Decode scalar log. |
| val slog = DecodeBits(op, "01111_00_00000_xxxxx_0xx_00000_11101_11") |
| |
| if (p.enableVector) { |
| // Vector length. |
| d.getvl := DecodeBits(op, "0001x_xx_xxxxx_xxxxx_000_xxxxx_11101_11") && op(26,25) =/= 3.U && (op(24,20) =/= 0.U || op(19,15) =/= 0.U) |
| d.getmaxvl := DecodeBits(op, "0001x_xx_00000_00000_000_xxxxx_11101_11") && op(26,25) =/= 3.U |
| |
| // Vector load/store. |
| d.vld := DecodeBits(op, "000xxx_0xxxxx_xxxxx0_xx_xxxxxx_x_111_11") // vld |
| |
| d.vst := DecodeBits(op, "001xxx_0xxxxx_xxxxx0_xx_xxxxxx_x_111_11") || // vst |
| DecodeBits(op, "011xxx_0xxxxx_xxxxx0_xx_xxxxxx_x_111_11") // vstq |
| |
| // Convolution transfer accumulators to vregs. Also decodes acset/actr ops. |
| val vconv = DecodeBits(op, "010100_000000_000000_xx_xxxxxx_x_111_11") |
| |
| // Duplicate |
| val vdup = DecodeBits(op, "01000x_0xxxxx_000000_xx_xxxxxx_x_111_11") && op(13,12) <= 2.U |
| val vdupi = vdup && op(26) === 0.U |
| |
| // Vector instructions. |
| d.viop := op(0) === 0.U || // .vv .vx |
| op(1,0) === 1.U || // .vvv .vxv |
| vconv || vdupi |
| } else { |
| d.getvl := false.B |
| d.getmaxvl := false.B |
| d.vld := false.B |
| d.vst := false.B |
| d.viop := false.B |
| } |
| |
| // [extensions] Core controls. |
| d.ebreak := DecodeBits(op, "000000000001_00000_000_00000_11100_11") |
| d.ecall := DecodeBits(op, "000000000000_00000_000_00000_11100_11") |
| d.eexit := DecodeBits(op, "000000100000_00000_000_00000_11100_11") |
| d.eyield := DecodeBits(op, "000001000000_00000_000_00000_11100_11") |
| d.ectxsw := DecodeBits(op, "000001100000_00000_000_00000_11100_11") |
| d.mpause := DecodeBits(op, "000010000000_00000_000_00000_11100_11") |
| d.mret := DecodeBits(op, "001100000010_00000_000_00000_11100_11") |
| |
| // Fences. |
| d.fencei := DecodeBits(op, "0000_0000_0000_00000_001_00000_0001111") |
| d.flushat := DecodeBits(op, "0010x_xx_00000_xxxxx_000_00000_11101_11") && op(19,15) =/= 0.U |
| d.flushall := DecodeBits(op, "0010x_xx_00000_00000_000_00000_11101_11") |
| |
| // [extensions] Scalar logging. |
| d.slog := slog |
| |
| // Stub out decoder state not used beyond pipeline0. |
| if (pipeline > 0) { |
| d.csrrw := false.B |
| d.csrrs := false.B |
| d.csrrc := false.B |
| |
| d.div := false.B |
| d.divu := false.B |
| d.rem := false.B |
| d.remu := false.B |
| |
| d.ebreak := false.B |
| d.ecall := false.B |
| d.eexit := false.B |
| d.eyield := false.B |
| d.ectxsw := false.B |
| d.mpause := false.B |
| d.mret := false.B |
| |
| d.fence := false.B |
| d.fencei := false.B |
| d.flushat := false.B |
| d.flushall := false.B |
| |
| d.slog := false.B |
| } |
| |
| // Generate the undefined opcode. |
| val decoded = Cat(d.lui, d.auipc, |
| d.jal, d.jalr, |
| d.beq, d.bne, d.blt, d.bge, d.bltu, d.bgeu, |
| d.csrrw, d.csrrs, d.csrrc, |
| d.lb, d.lh, d.lw, d.lbu, d.lhu, |
| d.sb, d.sh, d.sw, d.fence, |
| d.addi, d.slti, d.sltiu, d.xori, d.ori, d.andi, |
| d.add, d.sub, d.slt, d.sltu, d.xor, d.or, d.and, |
| d.slli, d.srli, d.srai, d.sll, d.srl, d.sra, |
| d.mul, d.mulh, d.mulhsu, d.mulhu, d.mulhr, d.mulhsur, d.mulhur, d.dmulh, d.dmulhr, |
| d.div, d.divu, d.rem, d.remu, |
| d.clz, d.ctz, d.pcnt, d.min, d.minu, d.max, d.maxu, |
| d.viop, d.vld, d.vst, |
| d.getvl, d.getmaxvl, |
| d.ebreak, d.ecall, d.eexit, d.eyield, d.ectxsw, |
| d.mpause, d.mret, d.fencei, d.flushat, d.flushall, d.slog) |
| |
| d.undef := !WiredOR(decoded) |
| |
| d |
| } |
| } |