| // 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 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 = Flipped(new AluIO(p)) |
| |
| // Branch interface. |
| val bru = Flipped(new BruIO(p)) |
| |
| // CSR interface. |
| val csr = Flipped(new CsrIO(p)) |
| |
| // LSU interface. |
| val lsu = Flipped(new LsuIO(p)) |
| |
| // Multiplier interface. |
| val mlu = Flipped(new MluIO(p)) |
| |
| // Divide interface. |
| val dvu = Flipped(new DvuIO(p)) |
| |
| // Vector interface. |
| val vinst = Flipped(new VInstIO) |
| |
| // 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 = Module(new DecodedInstruction(p, pipeline)) |
| d.io.addr := io.inst.addr |
| d.io.inst := io.inst.inst |
| |
| val vldst = d.io.vld || d.io.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 isAluImm = d.io.addi || d.io.slti || d.io.sltiu || d.io.xori || |
| d.io.ori || d.io.andi || d.io.slli || d.io.srli || d.io.srai |
| |
| val isAluReg = d.io.add || d.io.sub || d.io.slt || d.io.sltu || d.io.xor || |
| d.io.or || d.io.and || d.io.sll || d.io.srl || d.io.sra |
| |
| val isAlu1Bit = d.io.clz || d.io.ctz || d.io.pcnt |
| val isAlu2Bit = d.io.min || d.io.minu || d.io.max || d.io.maxu |
| |
| val isCondBr = d.io.beq || d.io.bne || d.io.blt || d.io.bge || |
| d.io.bltu || d.io.bgeu |
| |
| val isCsr = d.io.csrrw || d.io.csrrs || d.io.csrrc |
| val isCsrImm = isCsr && io.inst.inst(14) |
| val isCsrReg = isCsr && !io.inst.inst(14) |
| |
| val isLoad = d.io.lb || d.io.lh || d.io.lw || d.io.lbu || d.io.lhu |
| val isStore = d.io.sb || d.io.sh || d.io.sw |
| val isLsu = isLoad || isStore || d.io.vld || d.io.vst || d.io.flushat || d.io.flushall |
| |
| val isMul = d.io.mul || d.io.mulh || d.io.mulhsu || d.io.mulhu || d.io.mulhr || d.io.mulhsur || d.io.mulhur || d.io.dmulh || d.io.dmulhr |
| |
| val isDvu = d.io.div || d.io.divu || d.io.rem || d.io.remu |
| |
| val isVIop = io.vinst.op(new VInstOp().VIOP) |
| |
| 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 || isStore || isCondBr |
| val aluRs1En = !io.scoreboard.comb(rs1Addr) || isVIopVs1 || isLsu || d.io.auipc |
| val aluRs2En = !io.scoreboard.comb(rs2Addr) || isVIopVs2 || isLsu || d.io.auipc || isAluImm || 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.io.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 = !isLsu || |
| !io.serializeIn.lsu && io.lsu.ready && |
| (!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) && (isStore || vldst)) |
| |
| // Interlock mul, only one lane accepted. |
| val mulEn = (!isMul || !io.serializeIn.mul) && !io.serializeIn.brcond |
| |
| |
| // Vector extension interlock. |
| val vinstEn = !(io.serializeIn.vinst || isVIop && io.serializeIn.brcond) && |
| !(io.vinst.op =/= 0.U && !io.vinst.ready) |
| |
| // Fence interlock. |
| // Input mactive used passthrough, prefer to avoid registers in Decode. |
| val fenceEn = !(d.io.fence && io.mactive) |
| |
| // ALU opcode. |
| val alu = new AluOp() |
| val aluOp = Wire(Vec(alu.Entries, Bool())) |
| val aluValid = WiredOR(io.alu.op) // used without decodeEn |
| io.alu.valid := decodeEn && aluValid |
| io.alu.addr := rdAddr |
| io.alu.op := aluOp.asUInt |
| |
| aluOp(alu.ADD) := d.io.auipc || d.io.addi || d.io.add |
| aluOp(alu.SUB) := d.io.sub |
| aluOp(alu.SLT) := d.io.slti || d.io.slt |
| aluOp(alu.SLTU) := d.io.sltiu || d.io.sltu |
| aluOp(alu.XOR) := d.io.xori || d.io.xor |
| aluOp(alu.OR) := d.io.ori || d.io.or |
| aluOp(alu.AND) := d.io.andi || d.io.and |
| aluOp(alu.SLL) := d.io.slli || d.io.sll |
| aluOp(alu.SRL) := d.io.srli || d.io.srl |
| aluOp(alu.SRA) := d.io.srai || d.io.sra |
| aluOp(alu.LUI) := d.io.lui |
| aluOp(alu.CLZ) := d.io.clz |
| aluOp(alu.CTZ) := d.io.ctz |
| aluOp(alu.PCNT) := d.io.pcnt |
| aluOp(alu.MIN) := d.io.min |
| aluOp(alu.MINU) := d.io.minu |
| aluOp(alu.MAX) := d.io.max |
| aluOp(alu.MAXU) := d.io.maxu |
| |
| // 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.io.immjal, d.io.immbr) |
| io.bru.link := rdAddr |
| |
| bruOp(bru.JAL) := d.io.jal |
| bruOp(bru.JALR) := d.io.jalr |
| bruOp(bru.BEQ) := d.io.beq |
| bruOp(bru.BNE) := d.io.bne |
| bruOp(bru.BLT) := d.io.blt |
| bruOp(bru.BGE) := d.io.bge |
| bruOp(bru.BLTU) := d.io.bltu |
| bruOp(bru.BGEU) := d.io.bgeu |
| bruOp(bru.EBREAK) := d.io.ebreak |
| bruOp(bru.ECALL) := d.io.ecall |
| bruOp(bru.EEXIT) := d.io.eexit |
| bruOp(bru.EYIELD) := d.io.eyield |
| bruOp(bru.ECTXSW) := d.io.ectxsw |
| bruOp(bru.MPAUSE) := d.io.mpause |
| bruOp(bru.MRET) := d.io.mret |
| bruOp(bru.FENCEI) := d.io.fencei |
| bruOp(bru.UNDEF) := d.io.undef |
| |
| // CSR opcode. |
| val csr = new CsrOp() |
| val csrOp = Wire(Vec(csr.Entries, Bool())) |
| val csrValid = WiredOR(io.csr.op) // used without decodeEn |
| io.csr.valid := decodeEn && csrValid |
| io.csr.addr := rdAddr |
| io.csr.index := io.inst.inst(31,20) |
| io.csr.op := csrOp.asUInt |
| |
| csrOp(csr.CSRRW) := d.io.csrrw |
| csrOp(csr.CSRRS) := d.io.csrrs |
| csrOp(csr.CSRRC) := d.io.csrrc |
| |
| // LSU opcode. |
| val lsu = new LsuOp() |
| val lsuOp = Wire(Vec(lsu.Entries, Bool())) |
| val lsuValid = WiredOR(io.lsu.op) // used without decodeEn |
| io.lsu.valid := decodeEn && lsuValid |
| io.lsu.store := io.inst.inst(5) |
| io.lsu.addr := rdAddr |
| io.lsu.op := lsuOp.asUInt |
| |
| lsuOp(lsu.LB) := d.io.lb |
| lsuOp(lsu.LH) := d.io.lh |
| lsuOp(lsu.LW) := d.io.lw |
| lsuOp(lsu.LBU) := d.io.lbu |
| lsuOp(lsu.LHU) := d.io.lhu |
| lsuOp(lsu.SB) := d.io.sb |
| lsuOp(lsu.SH) := d.io.sh |
| lsuOp(lsu.SW) := d.io.sw |
| lsuOp(lsu.FENCEI) := d.io.fencei |
| lsuOp(lsu.FLUSHAT) := d.io.flushat |
| lsuOp(lsu.FLUSHALL) := d.io.flushall |
| |
| lsuOp(lsu.VLDST) := d.io.vld || d.io.vst |
| |
| // MLU opcode. |
| val mlu = new MluOp() |
| val mluOp = Wire(Vec(mlu.Entries, Bool())) |
| val mluValid = WiredOR(io.mlu.op) // used without decodeEn |
| io.mlu.valid := decodeEn && mluValid |
| io.mlu.addr := rdAddr |
| io.mlu.op := mluOp.asUInt |
| |
| mluOp(mlu.MUL) := d.io.mul |
| mluOp(mlu.MULH) := d.io.mulh |
| mluOp(mlu.MULHSU) := d.io.mulhsu |
| mluOp(mlu.MULHU) := d.io.mulhu |
| mluOp(mlu.MULHR) := d.io.mulhr |
| mluOp(mlu.MULHSUR) := d.io.mulhsur |
| mluOp(mlu.MULHUR) := d.io.mulhur |
| mluOp(mlu.DMULH) := d.io.dmulh |
| mluOp(mlu.DMULHR) := d.io.dmulhr |
| |
| // DIV opcode. |
| val dvu = new DvuOp() |
| val dvuOp = Wire(Vec(dvu.Entries, Bool())) |
| val dvuValid = WiredOR(io.dvu.op) // used without decodeEn |
| io.dvu.valid := decodeEn && dvuValid |
| io.dvu.addr := rdAddr |
| io.dvu.op := dvuOp.asUInt |
| |
| dvuOp(dvu.DIV) := d.io.div |
| dvuOp(dvu.DIVU) := d.io.divu |
| dvuOp(dvu.REM) := d.io.rem |
| dvuOp(dvu.REMU) := d.io.remu |
| |
| val dvuEn = WiredOR(io.dvu.op) === 0.U || io.dvu.ready |
| |
| // Vector instructions. |
| val vinst = new VInstOp() |
| val vinstOp = Wire(Vec(vinst.Entries, Bool())) |
| val vinstValid = WiredOR(vinstOp) // used without decodeEn |
| |
| io.vinst.valid := decodeEn && vinstValid |
| io.vinst.addr := rdAddr |
| io.vinst.inst := io.inst.inst |
| io.vinst.op := vinstOp.asUInt |
| |
| vinstOp(vinst.VLD) := d.io.vld |
| vinstOp(vinst.VST) := d.io.vst |
| vinstOp(vinst.VIOP) := d.io.viop |
| vinstOp(vinst.GETVL) := d.io.getvl |
| vinstOp(vinst.GETMAXVL) := d.io.getmaxvl |
| |
| // Scalar logging. |
| io.slog := decodeEn && d.io.slog |
| |
| // Register file read ports. |
| io.rs1Read.valid := decodeEn && (isCondBr || isAluReg || isAluImm || isAlu1Bit || isAlu2Bit || |
| isCsrImm || isCsrReg || isMul || isDvu || d.io.slog || |
| d.io.getvl || d.io.vld || d.io.vst) |
| io.rs2Read.valid := decodeEn && (isCondBr || isAluReg || isAlu2Bit || isStore || |
| isCsrReg || isMul || isDvu || d.io.slog || d.io.getvl || |
| d.io.vld || d.io.vst || d.io.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.io.auipc || isCsrImm) |
| io.rs2Set.valid := io.rs1Set.valid || decodeEn && (isAluImm || isAlu1Bit || d.io.lui) |
| |
| io.rs1Set.value := Mux(isCsr, d.io.immcsr, io.inst.addr) // Program Counter (PC) |
| |
| io.rs2Set.value := MuxCase(d.io.imm12, |
| IndexedSeq((d.io.auipc || d.io.lui) -> d.io.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 = |
| aluValid || csrValid || mluValid || dvuValid && io.dvu.ready || |
| lsuValid && isLoad || |
| d.io.getvl || d.io.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 := lsuValid |
| 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.io.flushat |
| io.busRead.immed := Cat(d.io.imm12(31,5), |
| Mux(storeSelect, d.io.immst(4,0), d.io.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.io.undef) |
| |
| // Serialize Interface. |
| // io.serializeOut.lsu := io.serializeIn.lsu || lsuValid || 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 || mluValid |
| io.serializeOut.jump := io.serializeIn.jump || d.io.jal || d.io.jalr || |
| d.io.ebreak || d.io.ecall || d.io.eexit || |
| d.io.eyield || d.io.ectxsw || d.io.mpause || d.io.mret |
| io.serializeOut.brcond := io.serializeIn.brcond | |
| d.io.beq || d.io.bne || d.io.blt || d.io.bge || d.io.bltu || d.io.bgeu |
| io.serializeOut.vinst := io.serializeIn.vinst |
| } |
| |
| class DecodedInstruction(p: Parameters, pipeline: Int) extends Module { |
| val io = IO(new Bundle { |
| val addr = Input(UInt(32.W)) |
| val inst = Input(UInt(32.W)) |
| |
| // Immediates |
| val imm12 = Output(UInt(32.W)) |
| val imm20 = Output(UInt(32.W)) |
| val immjal = Output(UInt(32.W)) |
| val immbr = Output(UInt(32.W)) |
| val immcsr = Output(UInt(32.W)) |
| val immst = Output(UInt(32.W)) |
| |
| // RV32I |
| val lui = Output(Bool()) |
| val auipc = Output(Bool()) |
| val jal = Output(Bool()) |
| val jalr = Output(Bool()) |
| val beq = Output(Bool()) |
| val bne = Output(Bool()) |
| val blt = Output(Bool()) |
| val bge = Output(Bool()) |
| val bltu = Output(Bool()) |
| val bgeu = Output(Bool()) |
| val csrrw = Output(Bool()) |
| val csrrs = Output(Bool()) |
| val csrrc = Output(Bool()) |
| val lb = Output(Bool()) |
| val lh = Output(Bool()) |
| val lw = Output(Bool()) |
| val lbu = Output(Bool()) |
| val lhu = Output(Bool()) |
| val sb = Output(Bool()) |
| val sh = Output(Bool()) |
| val sw = Output(Bool()) |
| val fence = Output(Bool()) |
| val addi = Output(Bool()) |
| val slti = Output(Bool()) |
| val sltiu = Output(Bool()) |
| val xori = Output(Bool()) |
| val ori = Output(Bool()) |
| val andi = Output(Bool()) |
| val slli = Output(Bool()) |
| val srli = Output(Bool()) |
| val srai = Output(Bool()) |
| val add = Output(Bool()) |
| val sub = Output(Bool()) |
| val slt = Output(Bool()) |
| val sltu = Output(Bool()) |
| val xor = Output(Bool()) |
| val or = Output(Bool()) |
| val and = Output(Bool()) |
| val sll = Output(Bool()) |
| val srl = Output(Bool()) |
| val sra = Output(Bool()) |
| |
| // RV32M |
| val mul = Output(Bool()) |
| val mulh = Output(Bool()) |
| val mulhsu = Output(Bool()) |
| val mulhu = Output(Bool()) |
| val mulhr = Output(Bool()) |
| val mulhsur = Output(Bool()) |
| val mulhur = Output(Bool()) |
| val dmulh = Output(Bool()) |
| val dmulhr = Output(Bool()) |
| val div = Output(Bool()) |
| val divu = Output(Bool()) |
| val rem = Output(Bool()) |
| val remu = Output(Bool()) |
| |
| // RV32B |
| val clz = Output(Bool()) |
| val ctz = Output(Bool()) |
| val pcnt = Output(Bool()) |
| val min = Output(Bool()) |
| val minu = Output(Bool()) |
| val max = Output(Bool()) |
| val maxu = Output(Bool()) |
| |
| // Vector instructions. |
| val getvl = Output(Bool()) |
| val getmaxvl = Output(Bool()) |
| val vld = Output(Bool()) |
| val vst = Output(Bool()) |
| val viop = Output(Bool()) |
| |
| // Core controls. |
| val ebreak = Output(Bool()) |
| val ecall = Output(Bool()) |
| val eexit = Output(Bool()) |
| val eyield = Output(Bool()) |
| val ectxsw = Output(Bool()) |
| val mpause = Output(Bool()) |
| val mret = Output(Bool()) |
| val undef = Output(Bool()) |
| |
| // Fences. |
| val fencei = Output(Bool()) |
| val flushat = Output(Bool()) |
| val flushall = Output(Bool()) |
| |
| // Scalar logging. |
| val slog = Output(Bool()) |
| }) |
| |
| val op = io.inst |
| |
| // Immediates |
| io.imm12 := Cat(Fill(20, op(31)), op(31,20)) |
| io.imm20 := Cat(op(31,12), 0.U(12.W)) |
| io.immjal := Cat(Fill(12, op(31)), op(19,12), op(20), op(30,21), 0.U(1.W)) |
| io.immbr := Cat(Fill(20, op(31)), op(7), op(30,25), op(11,8), 0.U(1.W)) |
| io.immcsr := op(19,15) |
| io.immst := Cat(Fill(20, op(31)), op(31,25), op(11,7)) |
| |
| // RV32I |
| io.lui := DecodeBits(op, "xxxxxxxxxxxxxxxxxxxx_xxxxx_0110111") |
| io.auipc := DecodeBits(op, "xxxxxxxxxxxxxxxxxxxx_xxxxx_0010111") |
| io.jal := DecodeBits(op, "xxxxxxxxxxxxxxxxxxxx_xxxxx_1101111") |
| io.jalr := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_000_xxxxx_1100111") |
| io.beq := DecodeBits(op, "xxxxxxx_xxxxx_xxxxx_000_xxxxx_1100011") |
| io.bne := DecodeBits(op, "xxxxxxx_xxxxx_xxxxx_001_xxxxx_1100011") |
| io.blt := DecodeBits(op, "xxxxxxx_xxxxx_xxxxx_100_xxxxx_1100011") |
| io.bge := DecodeBits(op, "xxxxxxx_xxxxx_xxxxx_101_xxxxx_1100011") |
| io.bltu := DecodeBits(op, "xxxxxxx_xxxxx_xxxxx_110_xxxxx_1100011") |
| io.bgeu := DecodeBits(op, "xxxxxxx_xxxxx_xxxxx_111_xxxxx_1100011") |
| io.csrrw := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_x01_xxxxx_1110011") |
| io.csrrs := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_x10_xxxxx_1110011") |
| io.csrrc := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_x11_xxxxx_1110011") |
| io.lb := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_000_xxxxx_0000011") |
| io.lh := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_001_xxxxx_0000011") |
| io.lw := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_010_xxxxx_0000011") |
| io.lbu := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_100_xxxxx_0000011") |
| io.lhu := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_101_xxxxx_0000011") |
| io.sb := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_000_xxxxx_0100011") |
| io.sh := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_001_xxxxx_0100011") |
| io.sw := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_010_xxxxx_0100011") |
| io.fence := DecodeBits(op, "0000_xxxx_xxxx_00000_000_00000_0001111") |
| io.addi := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_000_xxxxx_0010011") |
| io.slti := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_010_xxxxx_0010011") |
| io.sltiu := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_011_xxxxx_0010011") |
| io.xori := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_100_xxxxx_0010011") |
| io.ori := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_110_xxxxx_0010011") |
| io.andi := DecodeBits(op, "xxxxxxxxxxxx_xxxxx_111_xxxxx_0010011") |
| io.slli := DecodeBits(op, "0000000_xxxxx_xxxxx_001_xxxxx_0010011") |
| io.srli := DecodeBits(op, "0000000_xxxxx_xxxxx_101_xxxxx_0010011") |
| io.srai := DecodeBits(op, "0100000_xxxxx_xxxxx_101_xxxxx_0010011") |
| io.add := DecodeBits(op, "0000000_xxxxx_xxxxx_000_xxxxx_0110011") |
| io.sub := DecodeBits(op, "0100000_xxxxx_xxxxx_000_xxxxx_0110011") |
| io.slt := DecodeBits(op, "0000000_xxxxx_xxxxx_010_xxxxx_0110011") |
| io.sltu := DecodeBits(op, "0000000_xxxxx_xxxxx_011_xxxxx_0110011") |
| io.xor := DecodeBits(op, "0000000_xxxxx_xxxxx_100_xxxxx_0110011") |
| io.or := DecodeBits(op, "0000000_xxxxx_xxxxx_110_xxxxx_0110011") |
| io.and := DecodeBits(op, "0000000_xxxxx_xxxxx_111_xxxxx_0110011") |
| io.sll := DecodeBits(op, "0000000_xxxxx_xxxxx_001_xxxxx_0110011") |
| io.srl := DecodeBits(op, "0000000_xxxxx_xxxxx_101_xxxxx_0110011") |
| io.sra := DecodeBits(op, "0100000_xxxxx_xxxxx_101_xxxxx_0110011") |
| |
| // RV32M |
| io.mul := DecodeBits(op, "0000_001_xxxxx_xxxxx_000_xxxxx_0110011") |
| io.mulh := DecodeBits(op, "0000_001_xxxxx_xxxxx_001_xxxxx_0110011") |
| io.mulhsu := DecodeBits(op, "0000_001_xxxxx_xxxxx_010_xxxxx_0110011") |
| io.mulhu := DecodeBits(op, "0000_001_xxxxx_xxxxx_011_xxxxx_0110011") |
| io.mulhr := DecodeBits(op, "0010_001_xxxxx_xxxxx_001_xxxxx_0110011") |
| io.mulhsur := DecodeBits(op, "0010_001_xxxxx_xxxxx_010_xxxxx_0110011") |
| io.mulhur := DecodeBits(op, "0010_001_xxxxx_xxxxx_011_xxxxx_0110011") |
| io.dmulh := DecodeBits(op, "0000_010_xxxxx_xxxxx_001_xxxxx_0110011") |
| io.dmulhr := DecodeBits(op, "0010_010_xxxxx_xxxxx_001_xxxxx_0110011") |
| io.div := DecodeBits(op, "0000_001_xxxxx_xxxxx_100_xxxxx_0110011") |
| io.divu := DecodeBits(op, "0000_001_xxxxx_xxxxx_101_xxxxx_0110011") |
| io.rem := DecodeBits(op, "0000_001_xxxxx_xxxxx_110_xxxxx_0110011") |
| io.remu := DecodeBits(op, "0000_001_xxxxx_xxxxx_111_xxxxx_0110011") |
| |
| // RV32B |
| io.clz := DecodeBits(op, "0110000_00000_xxxxx_001_xxxxx_0010011") |
| io.ctz := DecodeBits(op, "0110000_00001_xxxxx_001_xxxxx_0010011") |
| io.pcnt := DecodeBits(op, "0110000_00010_xxxxx_001_xxxxx_0010011") |
| io.min := DecodeBits(op, "0000101_xxxxx_xxxxx_100_xxxxx_0110011") |
| io.minu := DecodeBits(op, "0000101_xxxxx_xxxxx_101_xxxxx_0110011") |
| io.max := DecodeBits(op, "0000101_xxxxx_xxxxx_110_xxxxx_0110011") |
| io.maxu := DecodeBits(op, "0000101_xxxxx_xxxxx_111_xxxxx_0110011") |
| |
| // Decode scalar log. |
| val slog = DecodeBits(op, "01111_00_00000_xxxxx_0xx_00000_11101_11") |
| |
| // Vector length. |
| io.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) |
| io.getmaxvl := DecodeBits(op, "0001x_xx_00000_00000_000_xxxxx_11101_11") && op(26,25) =/= 3.U |
| |
| // Vector load/store. |
| io.vld := DecodeBits(op, "000xxx_0xxxxx_xxxxx0_xx_xxxxxx_x_111_11") // vld |
| |
| io.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. |
| io.viop := op(0) === 0.U || // .vv .vx |
| op(1,0) === 1.U || // .vvv .vxv |
| vconv || vdupi |
| |
| // [extensions] Core controls. |
| io.ebreak := DecodeBits(op, "000000000001_00000_000_00000_11100_11") |
| io.ecall := DecodeBits(op, "000000000000_00000_000_00000_11100_11") |
| io.eexit := DecodeBits(op, "000000100000_00000_000_00000_11100_11") |
| io.eyield := DecodeBits(op, "000001000000_00000_000_00000_11100_11") |
| io.ectxsw := DecodeBits(op, "000001100000_00000_000_00000_11100_11") |
| io.mpause := DecodeBits(op, "000010000000_00000_000_00000_11100_11") |
| io.mret := DecodeBits(op, "001100000010_00000_000_00000_11100_11") |
| |
| // Fences. |
| io.fencei := DecodeBits(op, "0000_0000_0000_00000_001_00000_0001111") |
| io.flushat := DecodeBits(op, "0010x_xx_00000_xxxxx_000_00000_11101_11") && op(19,15) =/= 0.U |
| io.flushall := DecodeBits(op, "0010x_xx_00000_00000_000_00000_11101_11") |
| |
| // [extensions] Scalar logging. |
| io.slog := slog |
| |
| // Stub out decoder state not used beyond pipeline0. |
| if (pipeline > 0) { |
| io.csrrw := false.B |
| io.csrrs := false.B |
| io.csrrc := false.B |
| |
| io.div := false.B |
| io.divu := false.B |
| io.rem := false.B |
| io.remu := false.B |
| |
| io.ebreak := false.B |
| io.ecall := false.B |
| io.eexit := false.B |
| io.eyield := false.B |
| io.ectxsw := false.B |
| io.mpause := false.B |
| io.mret := false.B |
| |
| io.fence := false.B |
| io.fencei := false.B |
| io.flushat := false.B |
| io.flushall := false.B |
| |
| io.slog := false.B |
| } |
| |
| // Generate the undefined opcode. |
| val decoded = Cat(io.lui, io.auipc, |
| io.jal, io.jalr, |
| io.beq, io.bne, io.blt, io.bge, io.bltu, io.bgeu, |
| io.csrrw, io.csrrs, io.csrrc, |
| io.lb, io.lh, io.lw, io.lbu, io.lhu, |
| io.sb, io.sh, io.sw, io.fence, |
| io.addi, io.slti, io.sltiu, io.xori, io.ori, io.andi, |
| io.add, io.sub, io.slt, io.sltu, io.xor, io.or, io.and, |
| io.slli, io.srli, io.srai, io.sll, io.srl, io.sra, |
| io.mul, io.mulh, io.mulhsu, io.mulhu, io.mulhr, io.mulhsur, io.mulhur, io.dmulh, io.dmulhr, |
| io.div, io.divu, io.rem, io.remu, |
| io.clz, io.ctz, io.pcnt, io.min, io.minu, io.max, io.maxu, |
| io.viop, io.vld, io.vst, |
| io.getvl, io.getmaxvl, |
| io.ebreak, io.ecall, io.eexit, io.eyield, io.ectxsw, |
| io.mpause, io.mret, io.fencei, io.flushat, io.flushall, io.slog) |
| |
| io.undef := !WiredOR(decoded) |
| |
| // Delay the assert until the next cycle, so that logs appear on console. |
| val onehot_failed = RegInit(false.B) |
| assert(!onehot_failed) |
| |
| val onehot_decode = PopCount(decoded) |
| when ((onehot_decode + io.undef) =/= 1.U) { |
| onehot_failed := true.B |
| printf("[FAIL] decode inst=%x addr=%x decoded=0b%b pipeline=%d\n", |
| io.inst, io.addr, decoded, pipeline.U) |
| } |
| } |