Chisel 将枚举类型作为 IO

Chisel Passing Enum type as IO

这是一个关于凿子枚举的相关主题,我已经看过了 chisel "Enum(UInt(), 5)" failed

我正在用凿子构建 RISC-V,运行我遇到了障碍。我想将 ALU 操作码从操作码、funct3 和 funct7 的组合抽象为实际的 ALU 操作。下面我有一个 SystemVerilog 模块,它显示了我想要模拟的行为类型

// Defined in a types file
typedef enum bit [2:0] {
    alu_add = 3'b000,
    alu_sll = 3'b001,
    alu_sra = 3'b010,
    alu_sub = 3'b011,
    alu_xor = 3'b100,
    alu_srl = 3'b101,
    alu_or  = 3'b110,
    alu_and = 3'b111
} alu_ops;

module alu
(
    input alu_ops aluop,
    input [31:0] a, b,
    output logic [31:0] f
);

always_comb
begin
    unique case (aluop)
        alu_add:  f = a + b;
        alu_sll:  f = a << b[4:0];
        alu_sra:  f = $signed(a) >>> b[4:0];
        alu_sub:  f = a - b;
        alu_xor:  f = a ^ b;
        alu_srl:  f = a >> b[4:0];
        alu_or:   f = a | b;
        alu_and:  f = a & b;
    endcase
end

endmodule : alu

这是我当前使用的凿子文件

AluType.scala

import chisel3._
import chisel3.Driver
import chisel3.experimental.ChiselEnum

package ALUType {

  object AluOP extends ChiselEnum {
//    type AluOP = Value
    val ADDI, SLTI, SLTIU, XORI, ORI, ANDI, SLLI, SLRI, SRAI, ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND = Value
  }

}

AluFile.scala

import chisel3._
import chisel3.Driver
import chisel3.experimental.ChiselEnum
import ALUType.AluOP._

class ALUFile(val dl_size: Int, val op_size: Int, val funct3_size: Int, val funct7_size: Int) extends Module {
  val io = IO(new Bundle {
    val val_a       =  Input(UInt(dl_size.W))
    val val_b       =  Input(UInt(dl_size.W))
    val aluop       =  Input(ALUType.AluOP.Type)
    //val opcode      =  Input(UInt(op_size.W))
    //val funct3      =  Input(UInt(funct3_size.W))
    //val funct7      =  Input(UInt(funct7_size.W))
    val val_out     = Output(UInt(dl_size.W))
  })

// Actual function
}

这是 sbt 运行

的结果
$ sbt run
[info] welcome to sbt 1.4.7 (Oracle Corporation Java 1.8.0_281)
[info] loading project definition from C:\Chisel\Test1\RegFile\project
[info] loading settings for project regfile from build.sbt ...
[info] set current project to regfile (in build file:/C:/Chisel/Test1/RegFile/)
[info] compiling 1 Scala source to C:\Chisel\Test1\RegFile\target\scala-2.12\classes ...
[error] C:\Chisel\Test1\RegFile\src\main\scala\ALUFile.scala:43:30: inferred type arguments [ALUType.AluOP.Type.type] do not conform to method apply's type parameter bounds [T <: chisel3.Data]
[error]     val aluop       =  Input(Wire(ALUType.AluOP.Type))
[error]                              ^
[error] C:\Chisel\Test1\RegFile\src\main\scala\ALUFile.scala:43:49: type mismatch;
[error]  found   : ALUType.AluOP.Type.type
[error]  required: T
[error]     val aluop       =  Input(Wire(ALUType.AluOP.Type))
[error]                                                 ^
[error] two errors found
[error] (Compile / compileIncremental) Compilation failed
[error] Total time: 4 s, completed Feb 11, 2021 8:35:18 PM

我只需要将它分配给更高层的 UInt,然后再解码吗?似乎很愚蠢必须编码,然后解码只是为了将它从一个模块传递到下一个模块。有没有办法让 AluOP.Type 符合 T?我原以为它只是因为它是一个 ChiselEnum。

编辑:: 1

我尝试使用 UInt 进行枚举,但它说这是一个非文字类型

[info] running ALUFile
[info] [0.000] Elaborating design...
[error] chisel3.internal.ChiselException: AluOp defined with a non-literal type
[error]         ...
[error]         at AluOp$.<init>(ALUFile.scala:41)
[error]         at AluOp$.<clinit>(ALUFile.scala)
[error]         at ALUFile$$anon.<init>(ALUFile.scala:49)
[error]         at ALUFile.<init>(ALUFile.scala:46)
[error]         at ALUFile$.$anonfun$new(ALUFile.scala:80)
object AluOp extends ChiselEnum {
    val addi, slti, sltiu, xori, ori, andi, slli, slri, srai, add, sub, sll, slt, sltu, xor, srl, sra, or, and = Value(UInt()) // Line where error occurs
}
import AluOp._

class ALUFile(val dl_size: Int, val op_size: Int, val funct3_size: Int, val funct7_size: Int) extends Module {
  val io = IO(new Bundle {
    val val_a       =  Input(UInt(dl_size.W))
    val val_b       =  Input(UInt(dl_size.W))
    val aluop       =  Input( AluOp() )
    val val_out     = Output(UInt(dl_size.W))
  })

  switch (io.aluop) {
    is (addi) {
      io.val_out  := 1.U
    }
    is (slti) {
      io.val_out  := 2.U
    }
  }

  // Output result
  io.val_out  := 0.U

}

来自https://github.com/chipsalliance/chisel3/blob/dd6871b8b3f2619178c2a333d9d6083805d99e16/src/test/scala/chiselTests/StrongEnum.scala

这是他们在 switch 语句中使用枚举的唯一示例,但他们手动将值映射到不是枚举的类型!!!

object StrongEnumFSM {
  object State extends ChiselEnum {
    val sNone, sOne1, sTwo1s = Value

    val correct_annotation_map = Map[String, BigInt]("sNone" -> 0, "sOne1" -> 1, "sTwo1s" -> 2)
  }
}

class StrongEnumFSM extends Module {
  import StrongEnumFSM.State
  import StrongEnumFSM.State._

  // This FSM detects two 1's one after the other
  val io = IO(new Bundle {
    val in = Input(Bool())
    val out = Output(Bool())
    val state = Output(State())
  })

  val state = RegInit(sNone)

  io.out := (state === sTwo1s)
  io.state := state

  switch (state) {
    is (sNone) {
      when (io.in) {
        state := sOne1
      }
    }
    is (sOne1) {
      when (io.in) {
        state := sTwo1s
      } .otherwise {
        state := sNone
      }
    }
    is (sTwo1s) {
      when (!io.in) {
        state := sNone
      }
    }
  }
}

可以在此处找到一个可能存在的解决方案 https://github.com/chipsalliance/chisel3/issues/885,他在其中定义了自己的 Scala 对象并允许调用 return 一个 UInt。

此外,如果我只使用 Enum,我可以编译它,这可能是目前最好的解决方案。我希望看到 ChiselEnum 能够轻松地在 UInts 中定义状态或操作,并能够将它们作为 IO 传递,这样我就可以摆脱使用数字来定义状态并使它们更具可读性。

object AluOp {
        val addi :: slti :: sltiu :: xori :: ori :: andi :: slli :: slri :: srai :: add :: sub :: sll :: slt :: sltu :: xor :: srl :: sra :: or :: and :: Nil = Enum(19)
    }
import AluOp._

class ALUFile(val dl_size: Int, val op_size: Int, val funct3_size: Int, val funct7_size: Int) extends Module {
  val io = IO(new Bundle {
    val val_a       =  Input(UInt(dl_size.W))
    val val_b       =  Input(UInt(dl_size.W))
//    val aluop       =  Input( UInt(AluOp.getWidth.W) )
    val aluop       =  Input(UInt(5.W))
//    val opcode      =  Input(UInt(op_size.W))
//    val funct3      =  Input(UInt(funct3_size.W))
//    val funct7      =  Input(UInt(funct7_size.W))
    val val_out     = Output(UInt(dl_size.W))
  })
  //  val reg_last = RegNext()

  switch (io.aluop) {
    is (addi) {
      io.val_out  := 1.U
    }
    is (slti) {
      io.val_out  := 2.U
    }
  }

我想你需要做的就是使用

val aluop       =  Input(AluOP())

可以在 chisel3 unit tests

中找到一些简单的示例代码

OP 编辑​​::

通过添加映射:

import chisel3._
import chisel3.Driver
import chisel3.util._
import chisel3.experimental.ChiselEnum

package ALUType {
//    object AluOp {
//        val addi :: slti :: sltiu :: xori :: ori :: andi :: slli :: slri :: srai :: add :: sub :: sll :: slt :: sltu :: xor :: srl :: sra :: or :: and :: Nil = Enum(19)
//    }
    object AluOp extends ChiselEnum {
        val add, sub, sll, slt, sltu, xor, srl, sra, or, and = Value

        val correct_annotation_map = Map[String, UInt](
            "add"  -> 0.U,
            "sub"  -> 1.U,
            "sll"  -> 2.U,
            "slt"  -> 3.U,
            "sltu" -> 4.U,
            "xor"  -> 5.U,
            "srl"  -> 6.U,
            "sra"  -> 7.U,
            "or"   -> 8.U,
            "and"  -> 9.U
        )
    }
}

值可以作为输入传递:


import ALUType.AluOp._

class ALUFile(val dl_size: Int, val op_size: Int, val funct3_size: Int, val funct7_size: Int) extends Module {
  import ALUType._
  import ALUType.AluOp._
  val io = IO(new Bundle {
    val val_a       =  Input(UInt(dl_size.W))
    val val_b       =  Input(UInt(dl_size.W))
    val aluop       =  Input( AluOp() )
//    val aluop       =  Input(UInt(5.W))
//    val opcode      =  Input(UInt(op_size.W))
//    val funct3      =  Input(UInt(funct3_size.W))
//    val funct7      =  Input(UInt(funct7_size.W))
    val val_out     = Output(UInt(dl_size.W))
  })
//  switch (io.aluop) {
//    is (add) {
//      io.val_out  := io.val_a + io.val_b
//    }
//    is (slt) {
//      io.val_out  := 2.U
//    }
//  }

  switch (io.aluop) {
    is (add) {
      io.val_out  := io.val_a + io.val_b
    }
    is (slt) {
      io.val_out  := 2.U
    }
  }

  // Output result
  io.val_out  := 0.U

}

这仍然不理想,因为我不想手动将字符串映射到 UInt 值,但事实就是如此。也许 Scala foreach 循环可以解决繁琐的分配问题,谁知道呢。