diff --git a/src/main/scala/rvspeccore/checker/Checker.scala b/src/main/scala/rvspeccore/checker/Checker.scala index 7ed398d..1d75e55 100644 --- a/src/main/scala/rvspeccore/checker/Checker.scala +++ b/src/main/scala/rvspeccore/checker/Checker.scala @@ -91,20 +91,20 @@ class CheckerWithResult(val checkMem: Boolean = true, enableReg: Boolean = false if (checkMem) { if (!config.functions.tlb) { - assert(io.mem.get.read.valid === specCore.io.mem.read.valid) - when(io.mem.get.read.valid || specCore.io.mem.read.valid) { - assert(io.mem.get.read.addr === specCore.io.mem.read.addr) - assert(io.mem.get.read.memWidth === specCore.io.mem.read.memWidth) + assert(regDelay(io.mem.get.read.valid) === regDelay(specCore.io.mem.read.valid)) + when(regDelay(io.mem.get.read.valid || specCore.io.mem.read.valid)) { + assert(regDelay(io.mem.get.read.addr) === regDelay(specCore.io.mem.read.addr)) + assert(regDelay(io.mem.get.read.memWidth) === regDelay(specCore.io.mem.read.memWidth)) } - assert(io.mem.get.write.valid === specCore.io.mem.write.valid) - when(io.mem.get.write.valid || specCore.io.mem.write.valid) { - assert(io.mem.get.write.addr === specCore.io.mem.write.addr) - assert(io.mem.get.write.data === specCore.io.mem.write.data) - assert(io.mem.get.write.memWidth === specCore.io.mem.write.memWidth) + assert(regDelay(io.mem.get.write.valid) === regDelay(specCore.io.mem.write.valid)) + when(regDelay(io.mem.get.write.valid || specCore.io.mem.write.valid)) { + assert(regDelay(io.mem.get.write.addr) === regDelay(specCore.io.mem.write.addr)) + assert(regDelay(io.mem.get.write.data) === regDelay(specCore.io.mem.write.data)) + assert(regDelay(io.mem.get.write.memWidth) === regDelay(specCore.io.mem.write.memWidth)) } specCore.io.mem.read.data := io.mem.get.read.data } else { - // printf("[specCore] Valid:%x PC: %x Inst: %x\n", specCore.io.valid, specCore.io.now.pc, specCore.io.inst) + // printf("[SpecCore] Valid:%x PC: %x Inst: %x\n", specCore.io.valid, specCore.io.now.pc, specCore.io.inst) // specCore.io.mem.read.data := { if (checkMem) io.mem.get.read.data else DontCare } val TLBLoadQueue = Seq.fill(3)(Module(new QueueModuleTLB())) // initial the queue @@ -114,18 +114,6 @@ class CheckerWithResult(val checkMem: Boolean = true, enableReg: Boolean = false TLBLoadQueue(i).io.in.bits := 0.U.asTypeOf(new StoreOrLoadInfoTLB) } when(io.dtlbmem.get.read.valid) { - assert(RegNext(TLBLoadQueue(0).io.in.valid, false.B) === false.B) - assert(RegNext(TLBLoadQueue(0).io.in.bits.addr, 0.U) === 0.U) - assert(RegNext(TLBLoadQueue(0).io.in.bits.data, 0.U) === 0.U) - assert(RegNext(TLBLoadQueue(0).io.in.bits.level, 0.U) === 0.U) - assert(RegNext(TLBLoadQueue(1).io.in.valid, false.B) === false.B) - assert(RegNext(TLBLoadQueue(1).io.in.bits.addr, 0.U) === 0.U) - assert(RegNext(TLBLoadQueue(1).io.in.bits.data, 0.U) === 0.U) - assert(RegNext(TLBLoadQueue(1).io.in.bits.level, 0.U) === 0.U) - assert(RegNext(TLBLoadQueue(2).io.in.valid, false.B) === false.B) - assert(RegNext(TLBLoadQueue(2).io.in.bits.addr, 0.U) === 0.U) - assert(RegNext(TLBLoadQueue(2).io.in.bits.data, 0.U) === 0.U) - assert(RegNext(TLBLoadQueue(2).io.in.bits.level, 0.U) === 0.U) for (i <- 0 until 3) { when(io.dtlbmem.get.read.level === i.U) { @@ -139,12 +127,10 @@ class CheckerWithResult(val checkMem: Boolean = true, enableReg: Boolean = false for (i <- 0 until 3) { when(specCore.io.tlb.get.Anotherread(i).valid) { TLBLoadQueue(2 - i).io.out.ready := true.B - // printf("Load out Queue.... valid: %x %x %x %x\n", LoadQueue.io.out.valid, LoadQueue.io.out.bits.addr, LoadQueue.io.out.bits.data, LoadQueue.io.out.bits.memWidth) + // printf("[SpecCore] Load out Queue Valid: %x %x %x %x\n", LoadQueue.io.out.valid, LoadQueue.io.out.bits.addr, LoadQueue.io.out.bits.data, LoadQueue.io.out.bits.memWidth) specCore.io.tlb.get.Anotherread(i).data := { if (checkMem) TLBLoadQueue(2 - i).io.out.bits.data else DontCare } - // TODO: 第Level 1 assert is inconsistent nutshell and the condition need to modify. - // assert(TLBLoadQueue(i).io.out.bits.addr === specCore.io.mem.read.addr) } when(regDelay(specCore.io.tlb.get.Anotherread(i).valid)) { assert(regDelay(TLBLoadQueue(2 - i).io.out.bits.addr) === regDelay(specCore.io.tlb.get.Anotherread(i).addr)) @@ -158,17 +144,17 @@ class CheckerWithResult(val checkMem: Boolean = true, enableReg: Boolean = false LoadQueue.io.in.bits.addr := io.mem.get.read.addr LoadQueue.io.in.bits.data := io.mem.get.read.data LoadQueue.io.in.bits.memWidth := io.mem.get.read.memWidth - // printf("Load into Queue.... valid: %x %x %x %x\n", LoadQueue.io.in.valid, load_push.addr, load_push.data, load_push.memWidth) + // printf("[SpecCore] Load into Queue Valid: %x %x %x %x\n", LoadQueue.io.in.valid, load_push.addr, load_push.data, load_push.memWidth) }.otherwise { LoadQueue.io.in.valid := false.B LoadQueue.io.in.bits := 0.U.asTypeOf(new StoreOrLoadInfo) } - when(specCore.io.mem.read.valid) { + when(regDelay(specCore.io.mem.read.valid)) { LoadQueue.io.out.ready := true.B - // printf("Load out Queue.... valid: %x %x %x %x\n", LoadQueue.io.out.valid, LoadQueue.io.out.bits.addr, LoadQueue.io.out.bits.data, LoadQueue.io.out.bits.memWidth) + // printf("[SpecCore] Load out Queue Valid: %x %x %x %x\n", LoadQueue.io.out.valid, LoadQueue.io.out.bits.addr, LoadQueue.io.out.bits.data, LoadQueue.io.out.bits.memWidth) specCore.io.mem.read.data := LoadQueue.io.out.bits.data - assert(LoadQueue.io.out.bits.addr === specCore.io.mem.read.addr) - assert(LoadQueue.io.out.bits.memWidth === specCore.io.mem.read.memWidth) + assert(regDelay(LoadQueue.io.out.bits.addr) === regDelay(specCore.io.mem.read.addr)) + assert(regDelay(LoadQueue.io.out.bits.memWidth) === regDelay(specCore.io.mem.read.memWidth)) }.otherwise { LoadQueue.io.out.ready := false.B specCore.io.mem.read.data := 0.U @@ -180,17 +166,17 @@ class CheckerWithResult(val checkMem: Boolean = true, enableReg: Boolean = false StoreQueue.io.in.bits.addr := io.mem.get.write.addr StoreQueue.io.in.bits.data := io.mem.get.write.data StoreQueue.io.in.bits.memWidth := io.mem.get.write.memWidth - // printf("Store into Queue.... valid: %x %x %x %x\n", StoreQueue.io.in.valid, store_push.addr, store_push.data, store_push.memWidth) + // printf("[SpecCore] Store into Queue Valid: %x %x %x %x\n", StoreQueue.io.in.valid, store_push.addr, store_push.data, store_push.memWidth) }.otherwise { StoreQueue.io.in.valid := false.B StoreQueue.io.in.bits := 0.U.asTypeOf(new StoreOrLoadInfo) } - when(specCore.io.mem.write.valid) { + when(regDelay(specCore.io.mem.write.valid)) { StoreQueue.io.out.ready := true.B - // printf("Store out Queue.... valid: %x %x %x %x\n", StoreQueue.io.out.valid, StoreQueue.io.out.bits.addr, StoreQueue.io.out.bits.data, StoreQueue.io.out.bits.memWidth) - assert(StoreQueue.io.out.bits.addr === specCore.io.mem.write.addr) - assert(StoreQueue.io.out.bits.data === specCore.io.mem.write.data) - assert(StoreQueue.io.out.bits.memWidth === specCore.io.mem.write.memWidth) + // printf("[SpecCore] Store out Queue Valid: %x %x %x %x\n", StoreQueue.io.out.valid, StoreQueue.io.out.bits.addr, StoreQueue.io.out.bits.data, StoreQueue.io.out.bits.memWidth) + assert(regDelay(StoreQueue.io.out.bits.addr) === regDelay(specCore.io.mem.write.addr)) + assert(regDelay(StoreQueue.io.out.bits.data) === regDelay(specCore.io.mem.write.data)) + assert(regDelay(StoreQueue.io.out.bits.memWidth) === regDelay(specCore.io.mem.write.memWidth)) }.otherwise { StoreQueue.io.out.ready := false.B } @@ -200,25 +186,22 @@ class CheckerWithResult(val checkMem: Boolean = true, enableReg: Boolean = false } when(regDelay(io.instCommit.valid)) { - // next reg - for (i <- 0 until 32) { - assert(regDelay(io.result.reg(i.U)) === regDelay(specCore.io.next.reg(i.U))) - } - } - // printf("[SSD] io.instCommit.valid %x io.event.valid %x speccore.io.event.valid %x\n", io.instCommit.valid, io.event.valid, specCore.io.event.valid) - when(io.instCommit.valid) { // now pc: - assert(io.instCommit.pc === specCore.io.now.pc) + assert(regDelay(io.instCommit.pc) === regDelay(specCore.io.now.pc)) // next pc: hard to get next pc in a pipeline, check it at next instruction - // next csr: io.result.csr.table.zip(specCore.io.next.csr.table).map { case (result, next) => { - assert(result.signal === next.signal) + assert(regDelay(result.signal) === regDelay(next.signal)) } } + // next reg + for (i <- 0 until 32) { + assert(regDelay(io.result.reg(i.U)) === regDelay(specCore.io.next.reg(i.U))) + } } + when(regDelay(io.event.valid) || regDelay(specCore.io.event.valid)) { assert( regDelay(io.event.valid) === regDelay(specCore.io.event.valid) diff --git a/src/main/scala/rvspeccore/core/RVConfig.scala b/src/main/scala/rvspeccore/core/RVConfig.scala index 83e3a87..a6c704e 100644 --- a/src/main/scala/rvspeccore/core/RVConfig.scala +++ b/src/main/scala/rvspeccore/core/RVConfig.scala @@ -6,7 +6,7 @@ import chisel3.util._ case class RVConfig(configs: (String, Any)*) { private val acceptKeys = Map( "XLEN" -> Set("32", "64"), - "extensions" -> Set("I", "M", "C", "Zifencei", "Zicsr", "U", "S"), + "extensions" -> Set("I", "M", "C", "Zifencei", "Zicsr", "Zba", "Zbb", "Zbc", "Zbs", "U", "S"), "fakeExtensions" -> "ABCDEFGHIJKLMNOPQRSTUVWXYZ".map(_.toString).toSet, "initValue" -> Set("pc", "mstatus", "mtvec"), "functions" -> Set("Privileged", "TLB"), @@ -40,6 +40,11 @@ case class RVConfig(configs: (String, Any)*) { val C = raw.contains("C") val Zifencei = raw.contains("Zifencei") val Zicsr = raw.contains("Zicsr") + val Zba = raw.contains("Zba") + val Zbb = raw.contains("Zbb") + val Zbc = raw.contains("Zbc") + val Zbs = raw.contains("Zbs") + val B = Zba || Zbb || Zbc || Zbs // - RSIC-V ISA, Privileged, 20240411 // - 1. Introduction diff --git a/src/main/scala/rvspeccore/core/RiscvCore.scala b/src/main/scala/rvspeccore/core/RiscvCore.scala index c9af3a4..04cbb38 100644 --- a/src/main/scala/rvspeccore/core/RiscvCore.scala +++ b/src/main/scala/rvspeccore/core/RiscvCore.scala @@ -142,6 +142,7 @@ class RiscvTrans()(implicit config: RVConfig) extends BaseCore with RVInstSet { if (config.functions.privileged) doRVPrivileged if (config.extensions.Zicsr) doRVZicsr if (config.extensions.Zifencei) doRVZifencei + if (config.extensions.B) doRVBitManipulation // End excute next.reg(0) := 0.U diff --git a/src/main/scala/rvspeccore/core/spec/RVInstSet.scala b/src/main/scala/rvspeccore/core/spec/RVInstSet.scala index 9b03a1b..97bb433 100644 --- a/src/main/scala/rvspeccore/core/spec/RVInstSet.scala +++ b/src/main/scala/rvspeccore/core/spec/RVInstSet.scala @@ -13,3 +13,4 @@ trait RVInstSet with csr.CSRSupport with csr.ExceptionSupport with PrivilegedExtension + with BitManipulation diff --git a/src/main/scala/rvspeccore/core/spec/instset/BitManipulation.scala b/src/main/scala/rvspeccore/core/spec/instset/BitManipulation.scala new file mode 100644 index 0000000..eb80b94 --- /dev/null +++ b/src/main/scala/rvspeccore/core/spec/instset/BitManipulation.scala @@ -0,0 +1,375 @@ +package rvspeccore.core.spec.instset + +import chisel3._ +import chisel3.util._ + +import rvspeccore.core.BaseCore +import rvspeccore.core.spec._ +import rvspeccore.core.tool.BitTool._ + +/** "B" Extension for Bit Manipulation, Version 1.0.0 + * + * - riscv-spec-20240411 + * - Chapter 28: "B" Extension for Bit Manipulation, Version 1.0.0 + * - The B standard extension comprises instructions provided by the Zba, Zbb, and Zbs extensions. + */ +trait BitManipulationInsts { + val add_uw = Inst("b0000100_?????_?????_000_?????_0111011") + val andn = Inst("b0100000_?????_?????_111_?????_0110011") + val bclr = Inst("b0100100_?????_?????_001_?????_0110011") + val bclri = Inst( + 32 -> "b0100100_?????_?????_011_?????_0110011", + 64 -> "b010010_??????_?????_011_?????_0110011" + ) + val bext = Inst("b0100100_?????_?????_101_?????_0110011") + val bexti = Inst( + 32 -> "b0100100_?????_?????_101_?????_0010011", + 64 -> "b010010_??????_?????_101_?????_0010011" + ) + val binv = Inst("b0110100_?????_?????_001_?????_0110011") + val binvi = Inst( + 32 -> "b0110100_?????_?????_001_?????_0010011", + 64 -> "b011010_??????_?????_001_?????_0010011" + ) + val bseti = Inst( + 32 -> "b0010100_?????_?????_001_?????_0010011", + 64 -> "b001010_??????_?????_001_?????_0010011" + ) + val bset = Inst("b0010100_?????_?????_001_?????_0110011") + val clmul = Inst("b0000101_?????_?????_001_?????_0110011") + val clmulh = Inst("b0000101_?????_?????_011_?????_0110011") + val clmulr = Inst("b0000101_?????_?????_010_?????_0110011") + val clz = Inst("b0110000_00000_?????_001_?????_0010011") + val clzw = Inst("b0110000_00000_?????_001_?????_0011011") + val cpop = Inst("b0110000_00010_?????_001_?????_0010011") + val cpopw = Inst("b0110000_00010_?????_001_?????_0011011") + val ctz = Inst("b0110000_00001_?????_001_?????_0010011") + val ctzw = Inst("b0110000_00001_?????_001_?????_0011011") + val max = Inst("b0000101_?????_?????_110_?????_0110011") + val maxu = Inst("b0000101_?????_?????_111_?????_0110011") + val min = Inst("b0000101_?????_?????_100_?????_0110011") + val minu = Inst("b0000101_?????_?????_101_?????_0110011") + val orc_b = Inst("b001010000111_?????_101_?????_0010011") + val orn = Inst("b0100000_?????_?????_110_?????_0110011") + val pack = Inst("b0000100_?????_?????_100_?????_0110011") + val packh = Inst("b0000100_?????_?????_111_?????_0110011") + val packw = Inst("b0000100_?????_?????_100_?????_0111011") + val rev8 = Inst( + 32 -> "b011010011000_?????_101_?????_0010011", + 64 -> "b011010111000_?????_101_?????_0010011" + ) + val rev_b = Inst("b011010000111_?????_101_?????_0010011") + val rol = Inst("b0110000_?????_?????_001_?????_0110011") + val rolw = Inst("b0110000_?????_?????_001_?????_0111011") + val ror = Inst("b0110000_?????_?????_101_?????_0110011") + val rori = Inst( + 32 -> "b0110000_?????_?????_101_?????_0010011", + 64 -> "b011000_??????_?????_101_?????_0010011" + ) + val roriw = Inst("b0110000_?????_?????_101_?????_0011011") + val rorw = Inst("b0110000_?????_?????_101_?????_0111011") + val sext_b = Inst("b0110000_00100_?????_001_?????_0010011") + val sext_h = Inst("b0110000_00101_?????_001_?????_0010011") + val sh1add = Inst("b0010000_?????_?????_010_?????_0110011") + val sh1add_uw = Inst("b0010000_?????_?????_010_?????_0111011") + val sh2add = Inst("b0010000_?????_?????_100_?????_0110011") + val sh2add_uw = Inst("b0010000_?????_?????_100_?????_0111011") + val sh3add = Inst("b0010000_?????_?????_110_?????_0110011") + val sh3add_uw = Inst("b0010000_?????_?????_110_?????_0111011") + val slli_uw = Inst("b000010_??????_?????_001_?????_0011011") + val unzip = Inst("b0000100_11111_?????_101_?????_0010011") + val xnor = Inst("b0100000_?????_?????_100_?????_0110011") + val xperm_b= Inst("b0010100_?????_?????_100_?????_0110011") + val xperm_n= Inst("b0010100_?????_?????_010_?????_0110011") + val zext_h = Inst( + 32 -> "b0000100_00000_?????_100_?????_0110011", + 64 -> "b0000100_00000_?????_100_?????_0111011" + ) + val zip = Inst("b0000100_11110_?????_001_?????_0010011") +} + +/** "B" Extension for Bit Manipulation, Version 1.0.0 + * + * - riscv-spec-20240411 + * - Chapter 28: "B" Extension for Bit Manipulation, Version 1.0.0 + */ +trait BitManipulation extends BaseCore with CommonDecode with BitManipulationInsts { + def doRV32Zba: Unit = { + /** Address generation + * The Zba instructions can be used to accelerate the generation of addresses that index into arrays of + * basic types (halfword, word, doubleword) using both unsigned word-sized and XLEN-sized indices: a + * shifted index is added to a base address. + * - riscv-spec-20240411 P212 + * - Chapter 28.4.1 + */ + when(sh1add(inst)) {decodeR; next.reg(rd) := now.reg(rs2) + (now.reg(rs1) << 1)} + when(sh2add(inst)) { decodeR; next.reg(rd) := now.reg(rs2) + (now.reg(rs1) << 2) } + when(sh3add(inst)) { decodeR; next.reg(rd) := now.reg(rs2) + (now.reg(rs1) << 3) } + } + def doRV32Zbb: Unit = { + /** Basic bit-manipulation + * - riscv-spec-20240411 P212 + * - Chapter 28.4.2 + */ + // Logical with negate + when(andn(inst)) { decodeR; next.reg(rd) := now.reg(rs1) & (~now.reg(rs2)).asUInt } + when(orn(inst)) { decodeR; next.reg(rd) := now.reg(rs1) | (~now.reg(rs2)).asUInt } + when(xnor(inst)) { decodeR; next.reg(rd) := (~(now.reg(rs1) ^ now.reg(rs2))).asUInt } + // Count leading/trailing zero bits + when(clz(inst)) { decodeI; next.reg(rd) := Mux(now.reg(rs1) === 0.U, XLEN.U, PriorityEncoder(now.reg(rs1).asBools.reverse))} + when(ctz(inst)) { decodeI; next.reg(rd) := Mux(now.reg(rs1) === 0.U, XLEN.U, PriorityEncoder(now.reg(rs1).asBools))} + // Count population + when(cpop(inst)) { decodeI; next.reg(rd) := PopCount(now.reg(rs1)) } + // Integer minimum/maximum + when(max(inst)) { decodeR; next.reg(rd) := Mux(now.reg(rs1).asSInt < now.reg(rs2).asSInt, now.reg(rs2), now.reg(rs1)) } + when(maxu(inst)) { decodeR; next.reg(rd) := Mux(now.reg(rs1).asUInt < now.reg(rs2).asUInt, now.reg(rs2), now.reg(rs1)) } + when(min(inst)) { decodeR; next.reg(rd) := Mux(now.reg(rs1).asSInt < now.reg(rs2).asSInt, now.reg(rs1), now.reg(rs2)) } + when(minu(inst)) { decodeR; next.reg(rd) := Mux(now.reg(rs1).asUInt < now.reg(rs2).asUInt, now.reg(rs1), now.reg(rs2)) } + // Sign- and zero-extension + when(sext_b(inst)) { decodeI; next.reg(rd) := signExt(now.reg(rs1)(7, 0), XLEN) } + when(sext_h(inst)) { decodeI; next.reg(rd) := signExt(now.reg(rs1)(15, 0), XLEN) } + when(zext_h(inst)) { decodeI; next.reg(rd) := zeroExt(now.reg(rs1)(15, 0), XLEN) } + // Bitwise rotation + // Function to select the appropriate bit width based on XLEN + def getRotationShamt(value: UInt, xlen: Int): UInt = { + value(if (xlen == 32) 4 else 5, 0) + } + when(rol(inst)) { decodeR; next.reg(rd) := (now.reg(rs1) << getRotationShamt(now.reg(rs2), XLEN)).asUInt | (now.reg(rs1) >> (XLEN.U - getRotationShamt(now.reg(rs2), XLEN))).asUInt } + when(ror(inst)) { decodeR; next.reg(rd) := (now.reg(rs1) >> getRotationShamt(now.reg(rs2), XLEN)).asUInt | (now.reg(rs1) << (XLEN.U - getRotationShamt(now.reg(rs2), XLEN))).asUInt } + when(rori(inst)){ decodeI; next.reg(rd) := (now.reg(rs1) >> getRotationShamt(imm, XLEN)).asUInt | (now.reg(rs1) << (XLEN.U - getRotationShamt(imm, XLEN))).asUInt } + // OR Combine + when(orc_b(inst)) { + decodeR; + val byteResults = VecInit(Seq.fill(XLEN / 8)(0.U(8.W))) + for (i <- 0 until XLEN by 8) { + val byte = now.reg(rs1)(i + 7, i) + byteResults(i / 8) := Mux(byte.orR, 0xFF.U(8.W), 0x00.U(8.W)) + } + next.reg(rd) := byteResults.asUInt + } + // Byte-reverse + when(rev8(inst)) { + decodeR; + var result = 0.U(XLEN.W) + var j = XLEN - 8 + for (i <- 0 until XLEN by 8) { + result = result | (now.reg(rs1)(j + 7, j) << i).asUInt + j -= 8 + } + next.reg(rd) := result + } + + } + def doRV32Zbc: Unit = { + /** Carry-less multiplication + * - riscv-spec-20240411 P214 + * - Chapter 28.4.3 + * Carry-less multiplication is the multiplication in the polynomial ring over GF(2). + */ + when(clmul(inst)) { + decodeR; + val partialResults = VecInit(Seq.fill(XLEN)(0.U(XLEN.W))) + for (i <- 0 until XLEN) { + when(((now.reg(rs2) >> i.U) & 1.U) > 0.U) { + partialResults(i) := now.reg(rs1) << i + } + } + next.reg(rd) := partialResults.reduce(_ ^ _) + } + when(clmulh(inst)) { + decodeR; + val partialResults = VecInit(Seq.fill(XLEN)(0.U(XLEN.W))) + for (i <- 1 to XLEN) { + when(((now.reg(rs2) >> i.U) & 1.U) > 0.U) { + partialResults(i - 1) := now.reg(rs1) >> (XLEN - i) + } + } + next.reg(rd) := partialResults.reduce(_ ^ _) + } + when(clmulr(inst)) { + decodeR; + val partialResults = VecInit(Seq.fill(XLEN)(0.U(XLEN.W))) + for (i <- 0 until XLEN) { + when(((now.reg(rs2) >> i.U) & 1.U) > 0.U) { + partialResults(i) := now.reg(rs1) >> (XLEN - i - 1) + } + } + next.reg(rd) := partialResults.reduce(_ ^ _) + } + + } + def doRV32Zbs: Unit = { + /** Single-bit instructions + * - riscv-spec-20240411 P215 + * - Chapter 28.4.4 + * The single-bit instructions provide a mechanism to set, clear, invert, or extract a single bit in a register. + * The bit is specified by its index. + */ + when(bclr(inst)) {} + when(bclri(inst)) {} + when(bext(inst)) {} + when(bexti(inst)) {} + when(binv(inst)) {} + when(binvi(inst)) {} + when(bset(inst)) {} + when(bseti(inst)) {} + } + + def doRV64Zba(): Unit = { + doRV32Zba + when(add_uw(inst)) { + decodeR; next.reg(rd) := now.reg(rs2) + zeroExt(now.reg(rs1)(31, 0), XLEN) + } + when(sh1add_uw(inst)) { + decodeR; next.reg(rd) := now.reg(rs2) + (zeroExt(now.reg(rs1)(31, 0), XLEN) << 1) + } + when(sh2add_uw(inst)) { + decodeR; next.reg(rd) := now.reg(rs2) + (zeroExt(now.reg(rs1)(31, 0), XLEN) << 2) + } + when(sh3add_uw(inst)) { + decodeR; next.reg(rd) := now.reg(rs2) + (zeroExt(now.reg(rs1)(31, 0), XLEN) << 3) + } + when(slli_uw(inst)) { + decodeI; next.reg(rd) := zeroExt(now.reg(rs1)(31, 0), XLEN) << imm(5, 0) + } + // pseudoinstructions: zext.w rd, rs(Add unsigned word) + } + def doRV64Zbb(): Unit = { + doRV32Zbb + // Count leading/trailing zero bits + when(clzw(inst)) { decodeI; next.reg(rd) := Mux(now.reg(rs1) === 0.U, 32.U, PriorityEncoder(now.reg(rs1)(31, 0).asBools.reverse)) } + when(ctzw(inst)) { decodeI; next.reg(rd) := Mux(now.reg(rs1) === 0.U, 32.U, PriorityEncoder(now.reg(rs1)(31, 0).asBools)) } + // Count population + when(cpopw(inst)) { decodeI; next.reg(rd) := PopCount(now.reg(rs1)(31, 0)) } + // Sign- and zero-extension + when(zext_h(inst)) { decodeI; next.reg(rd) := zeroExt(now.reg(rs1)(15, 0), XLEN) } + // Bitwise rotation + // rori(64Bit) has been implemented in RV32Zbb + when(rolw(inst)) { + decodeR; + val rs1_data = zeroExt(now.reg(rs1)(31, 0), XLEN) + val result = ((rs1_data << now.reg(rs2)(4, 0)).asUInt | (rs1_data >> (32.U - now.reg(rs2)(4, 0))).asUInt) + next.reg(rd) := signExt(result(31, 0), XLEN) + } + when(roriw(inst)) { + decodeI; + val rs1_data = zeroExt(now.reg(rs1)(31, 0), XLEN) + val result = (rs1_data >> imm(4, 0)).asUInt | (rs1_data << (32.U - imm(4, 0))).asUInt + next.reg(rd) := signExt(result(31, 0), XLEN) + } + when(rorw(inst)) { + decodeR; + val rs1_data = zeroExt(now.reg(rs1)(31, 0), XLEN) + val result = (rs1_data >> now.reg(rs2)(4, 0)).asUInt | (rs1_data << (32.U - now.reg(rs2)(4, 0))).asUInt + next.reg(rd) := signExt(result(31, 0), XLEN) + } + + // Byte-reverse + when(rev8(inst)) { + decodeR; + var result = 0.U(XLEN.W) + var j = XLEN - 8 + for (i <- 0 until XLEN by 8) { + result = result | (now.reg(rs1)(j + 7, j) << i).asUInt + j -= 8 + } + next.reg(rd) := result + } + } + def doRV64Zbc(): Unit = { + doRV32Zbc + } + def doRV64Zbs(): Unit = { + doRV32Zbs + when(bclri(inst)) {} + when(bexti(inst)) {} + when(binvi(inst)) {} + when(bseti(inst)) {} + } + + def doRV32Zbkb: Unit = { + /** Bit-manipulation for Cryptography + * - riscv-spec-20240411 P215 + * - Chapter 28.4.5 + * This extension contains instructions essential for implementing common operations in cryptographic + * workloads. + */ + when(pack(inst)) {} + when(packh(inst)) {} + when(rev_b(inst)) {} + + } + def doRV32Zbkc: Unit = { + /** Carry-less multiplication for Cryptography + * - riscv-spec-20240411 P216 + * - Chapter 28.4.6 + * Carry-less multiplication is the multiplication in the polynomial ring over GF(2). This is a critical + * operation in some cryptographic workloads, particularly the AES-GCM authenticated encryption + * scheme. This extension provides only the instructions needed to efficiently implement the GHASH + * operation, which is part of this workload. + */ + } + def doRV32Zbkx: Unit = { + /** Crossbar permutations + * - riscv-spec-20240411 P216 + * - Chapter 28.4.7 + * These instructions implement a "lookup table" for 4 and 8 bit elements inside the general purpose + * registers. rs1 is used as a vector of N-bit words, and rs2 as a vector of N-bit indices into rs1. Elements in + * rs1 are replaced by the indexed element in rs2, or zero if the index into rs2 is out of bounds. + * These instructions are useful for expressing N-bit to N-bit boolean operations, and implementing + * cryptographic code with secret dependent memory accesses (particularly SBoxes) such that the + * execution latency does not depend on the (secret) data being operated on. + */ + when(xperm_b(inst)) {} + when(xperm_n(inst)) {} + } + + def doRV64Zbkb(): Unit = { + doRV32Zbkb + when(packw(inst)) {} + when(zip(inst)) {} + when(unzip(inst)) {} + } + def doRV64Zbkc(): Unit = { + doRV32Zbkc + } + def doRV64Zbkx(): Unit = { + doRV32Zbkx + } + + def doRV32BitManipulation: Unit = { + if(config.extensions.Zba){ + doRV32Zba + } + if(config.extensions.Zbb){ + doRV32Zbb + } + if(config.extensions.Zbc){ + doRV32Zbc + } + if(config.extensions.Zbs){ + doRV32Zbs + } + } + def doRV64BitManipulation: Unit = { + doRV32BitManipulation + if(config.extensions.Zba){ + doRV64Zba + } + if(config.extensions.Zbb){ + doRV64Zbb + } + if(config.extensions.Zbc){ + doRV64Zbc + } + if(config.extensions.Zbs){ + doRV64Zbs + } + } + def doRVBitManipulation(): Unit = { + config.XLEN match { + case 32 => doRV32BitManipulation + case 64 => doRV64BitManipulation + } + } +} diff --git a/src/main/scala/rvspeccore/core/spec/instset/IBase.scala b/src/main/scala/rvspeccore/core/spec/instset/IBase.scala index af11673..3657e94 100644 --- a/src/main/scala/rvspeccore/core/spec/instset/IBase.scala +++ b/src/main/scala/rvspeccore/core/spec/instset/IBase.scala @@ -182,20 +182,15 @@ trait IBase extends BaseCore with CommonDecode with IBaseInsts with ExceptionSup // NOP is encoded as ADDI x0, x0, 0. // - 2.5 Control Transfer Instructions - // FIXME: 全部的跳转指令都得加一次判断 并且之后需要在最后统一仲裁优先级 // - Unconditional Jumps // JAL when(JAL(inst)) { decodeJ; - // global_data.setpc := true.B; - // next.pc := now.pc + imm; - // next.reg(rd) := now.pc + 4.U; when(addrAligned(getfetchSize(), now.pc + imm)) { global_data.setpc := true.B; next.pc := now.pc + imm; next.reg(rd) := now.pc + 4.U; }.otherwise { - // FIXME: 没有赋值成功 next.csr.mtval := now.pc + imm; raiseException(MExceptionCode.instructionAddressMisaligned) } @@ -208,7 +203,6 @@ trait IBase extends BaseCore with CommonDecode with IBaseInsts with ExceptionSup next.pc := Cat((now.reg(rs1) + imm)(XLEN - 1, 1), 0.U(1.W)); next.reg(rd) := now.pc + 4.U; }.otherwise { - // FIXME: 没有赋值成功 next.csr.mtval := Cat((now.reg(rs1) + imm)(XLEN - 1, 1), 0.U(1.W)) raiseException(MExceptionCode.instructionAddressMisaligned) } @@ -222,26 +216,21 @@ trait IBase extends BaseCore with CommonDecode with IBaseInsts with ExceptionSup global_data.setpc := true.B; next.pc := now.pc + imm; }.otherwise { - // FIXME: 没有赋值成功 next.csr.mtval := now.pc + imm; raiseException(MExceptionCode.instructionAddressMisaligned) } - // global_data.setpc := true.B; next.pc := now.pc + imm } } when(BNE(inst)) { decodeB; - // printf("BNE: rs%d_left: %x, rs%d_right: %x\n", rs1, now.reg(rs1), rs2, now.reg(rs2)) when(now.reg(rs1) =/= now.reg(rs2)) { when(addrAligned(getfetchSize(), now.pc + imm)) { global_data.setpc := true.B; next.pc := now.pc + imm; }.otherwise { - // FIXME: 没有赋值成功 next.csr.mtval := now.pc + imm; raiseException(MExceptionCode.instructionAddressMisaligned) } - // global_data.setpc := true.B; next.pc := now.pc + imm } } // BLT[U] @@ -296,19 +285,17 @@ trait IBase extends BaseCore with CommonDecode with IBaseInsts with ExceptionSup } // - 2.6 Load and Store Instructions // LOAD - // TODO: LBU and LHU ? when(LB(inst)) { - // TODO: LB好像不会出现非对齐访存的异常? decodeI; when(addrAligned(SizeOp.b, now.reg(rs1) + imm)) { next.reg(rd) := signExt(memRead(now.reg(rs1) + imm, 8.U)(7, 0), XLEN) }.otherwise { + // TODO: LB doesn't seem to get an exception for unaligned access mem.read.addr := now.reg(rs1) + imm raiseException(MExceptionCode.loadAddressMisaligned) } } when(LH(inst)) { - // printf("[Debug]LH Begin: Reg%x:%x %x %x\n",rs1,now.reg(rs1),imm,rd) decodeI; when(addrAligned(SizeOp.h, now.reg(rs1) + imm)) { next.reg(rd) := signExt(memRead(now.reg(rs1) + imm, 16.U)(15, 0), XLEN) @@ -316,11 +303,8 @@ trait IBase extends BaseCore with CommonDecode with IBaseInsts with ExceptionSup mem.read.addr := now.reg(rs1) + imm raiseException(MExceptionCode.loadAddressMisaligned) } - // alignedException("Load", SizeOp.h, now.reg(rs1) + imm); - // printf("[Debug]LH End: %x\n",next.reg(rd)) } when(LW(inst)) { - // printf("[Debug]LW Begin: Reg:%x, Addr: %x TargetReg: %x\n",rs1,now.reg(rs1) + imm,rd) decodeI; when(addrAligned(SizeOp.w, now.reg(rs1) + imm)) { next.reg(rd) := signExt(memRead(now.reg(rs1) + imm, 32.U)(31, 0), XLEN) @@ -328,7 +312,6 @@ trait IBase extends BaseCore with CommonDecode with IBaseInsts with ExceptionSup mem.read.addr := now.reg(rs1) + imm raiseException(MExceptionCode.loadAddressMisaligned) } - // printf("[Debug]LW End: %x\n", next.reg(rd)) } when(LBU(inst)) { decodeI; alignedException("Load", SizeOp.b, rs2); next.reg(rd) := zeroExt(memRead(now.reg(rs1) + imm, 8.U)(7, 0), XLEN) } when(LHU(inst)) { @@ -373,7 +356,7 @@ trait IBase extends BaseCore with CommonDecode with IBaseInsts with ExceptionSup is(0x1.U) { raiseException(MExceptionCode.environmentCallFromSmode) } is(0x0.U) { raiseException(MExceptionCode.environmentCallFromUmode) } } - // printf("IS ECALL\n") + printf("IS ECALL, PrivilegeMode: %d\n", now.internal.privilegeMode) } when(FENCE(inst)) { decodeI /* then do nothing for now */ @@ -423,7 +406,7 @@ trait IBase extends BaseCore with CommonDecode with IBaseInsts with ExceptionSup // - 5.3 Load and Store Instructions RV64 // - LOAD - // FIXME: 并非所有的都加了异常访存的限制 需要重新梳理并新加 + // FIXME: Not all of them have added the exception access limit, which needs to be reorganized and added. when(LWU(inst)) { decodeI; when(addrAligned(SizeOp.w, now.reg(rs1) + imm)) { diff --git a/src/main/scala/rvspeccore/core/spec/instset/csr/CSRSupport.scala b/src/main/scala/rvspeccore/core/spec/instset/csr/CSRSupport.scala index 45b46c0..d81dc66 100644 --- a/src/main/scala/rvspeccore/core/spec/instset/csr/CSRSupport.scala +++ b/src/main/scala/rvspeccore/core/spec/instset/csr/CSRSupport.scala @@ -23,7 +23,7 @@ trait CSRSupport extends BaseCore with ExceptionSupport { val has: Bool = MuxLookup(addr, false.B)(now.csr.table.map { x => x.info.addr -> true.B }) val nowCSR: UInt = MuxLookup(addr, 0.U)(now.csr.table.map { x => x.info.addr -> x.signal }) val rmask: UInt = MuxLookup(addr, 0.U)(now.csr.table.map { x => x.info.addr -> x.info.rmask(XLEN) }) - // printf("[Debug]CSR_READ:(Have:%d, nowCSR:%x, Addr: %x %x)\n",has,nowCSR,addr,next.reg(1)) +// printf("[Debug]CSR_READ:(Have:%d, nowCSR:%x, Addr: %x %x)\n",has,nowCSR,addr,next.reg(1)) val rData = WireInit(0.U(XLEN.W)) def doCSRRead(MXLEN: Int): Unit = { @@ -65,15 +65,12 @@ trait CSRSupport extends BaseCore with ExceptionSupport { val csrPairs = now.csr.table.zip(next.csr.table) csrPairs.foreach { case (CSRInfoSignal(info, nowCSR), CSRInfoSignal(_, nextCSR)) => when(addr === info.addr) { - // 地址是当前寄存器的地址 // printf("[Debug]Find ADDR, %x %x\n", (info.wfn != null).B, (info.wmask != UnwritableMask).B) if (info.wfn.isDefined && info.wmask(XLEN) != UnwritableMask) { - // 且该寄存器可写 使用mask nextCSR := info.wfn.get(XLEN)((nowCSR & ~info.wmask(XLEN)) | (data & info.wmask(XLEN))) // printf("[Debug]CSR_Write:(Addr: %x, nowCSR: %x, nextCSR: %x)\n", addr, nowCSR, nextCSR) } else { // TODO: might cause some exception? - } } } @@ -126,7 +123,7 @@ trait CSRSupport extends BaseCore with ExceptionSupport { // FIXME: is mstatus not sstatus ? mstatusNew.sie := mstatusOld.spie next.internal.privilegeMode := Cat(0.U(1.W), mstatusOld.spp) - mstatusNew.spie := true.B // 正确的 + mstatusNew.spie := true.B mstatusNew.spp := ModeU mstatusNew.mprv := 0x0.U // Volume II P21 " If xPP != M, xRET also sets MPRV = 0 " next.csr.mstatus := mstatusNew.asUInt diff --git a/src/test/scala/rvspeccore/core/RiscvCoreSpec.scala b/src/test/scala/rvspeccore/core/RiscvCoreSpec.scala index 903ded6..12142f2 100644 --- a/src/test/scala/rvspeccore/core/RiscvCoreSpec.scala +++ b/src/test/scala/rvspeccore/core/RiscvCoreSpec.scala @@ -196,9 +196,13 @@ class RiscvCoreSpec extends AnyFlatSpec with ChiselScalatestTester { } class RiscvCore64Spec extends AnyFlatSpec with ChiselScalatestTester { - implicit val config = RVConfig(64, "MCZifencei") + implicit val config = RVConfig( + XLEN = 64, + extensions = "MCZifenceiZicsrZbaZbbZbc", + functions = Seq("Privileged"), + ) - val tests = Seq("rv64ui", "rv64um", "rv64uc") + val tests = Seq("rv64ui", "rv64um", "rv64uc", "rv64uzba", "rv64uzbb", "rv64uzbc") // NOTE: funce.i shows passed test, but RiscvCore not support it. // Because RiscvCore is too simple. @@ -217,11 +221,13 @@ class RiscvCore64Spec extends AnyFlatSpec with ChiselScalatestTester { } class RiscvCore32Spec extends AnyFlatSpec with ChiselScalatestTester { - implicit val config = RVConfig(32, "MCZifencei") - - val tests = Seq("rv32ui", "rv32um", "rv32uc") - // val tests = Seq("tempcsr32") + implicit val config = RVConfig( + XLEN = 32, + extensions = "MCZifenceiZicsrZbaZbbZbc", + functions = Seq("Privileged"), + ) + val tests = Seq("rv32ui", "rv32um", "rv32uc", "rv32uzba", "rv32uzbb", "rv32uzbc") // NOTE: funce.i shows passed test, but RiscvCore not support it. // Because RiscvCore is too simple. behavior of s"RiscvCore with ${config.getClass().getSimpleName()}"