我正在将Verilog项目重写为Chisel HDL。该项目具有几个解耦的子组件,例如[ex.v
,mem.v
或wb.v
),以及一个名为defines.v
的配置文件,该文件在子组件中为`included
。例如,
defines.v
中的内容
`define RstEnable 1'b1
`define RstDisable 1'b0
`define ZeroWord 32'h00000000
`define WriteEnable 1'b1
`define WriteDisable 1'b0
`define ReadEnable 1'b1
`define ReadDisable 1'b0
... ...
ex.v
中的内容
`include "defines.v"
module ex(
input wire rst,
input wire[`AluOpBus] aluop_i,
input wire[`AluSelBus] alusel_i,
input wire[`RegBus] reg1_i,
input wire[`RegBus] reg2_i,
... ...
);
always @ (*) begin
if(rst == `RstEnable) begin
logicout <= `ZeroWord;
end else begin
case (aluop_i);
`EXE_OR_OP: begin
logicout <= reg1_i | reg2_i;
end
`EXE_AND_OP: begin
logicout <= reg1_i & reg2_i;
end
... ...
default: begin
logicout <= `ZeroWord;
end
endcase
end //if
end //always
... ...
endmodule
我不熟悉Scala,因此其新的LISP风格的宏系统对我来说太强大了,无法完全理解。我想要的只是一个简单的C / C ++预处理程序样式宏,它可以进行文本替换。
我尝试使用变量
package cpu
import chisel3._
import chisel3.util._
object Defines {
val RstEnable = "b1".U(1.W)
val RstDisable = "b0".U(1.W)
... ...
}
在Scala中使用变量定义如下
class Ex extends Module {
val io = IO(new Bundle {
... ...
val aluop_i = Input(UInt(AluOpBus))
... ...
})
... ...
logicout := io.aluop_i match {
case EXE_OR_OP => logicout
case _ => 0.U
}
}
这几乎可行,除了以下错误表明match
对变量不满意
[error] /Users/nalzok/Developer/DonkeyMIPS/chisel/src/main/scala/cpu/ex/Ex.scala:88:10: type mismatch;
[error] found : chisel3.UInt
[error] required: Unit
[error] case EXE_OR_OP => logicout
[error] ^
[error] one error found
[error] (Compile / compileIncremental) Compilation failed
[error] Total time: 3 s, completed Jun 14, 2020 9:42:13 AM
logicout := io.aluop_i
返回时进行模式匹配。进行硬件连接,返回Unit
,然后您尝试在其上进行模式匹配。Chisel并未将Scala条件/模式匹配转换为硬件构造。因此,模式匹配不能用于描述硬件多路复用(Scalamatch
/ case
不是Verilog case
)。但是,您确实具有Scala条件/模式匹配的全部功能来描述
硬件生成。例如,您可以在RstEnable
上进行模式匹配以产生具有或不具有复位功能的硬件。
when
/.elsewhen
/.otherwise
或when
。类似于:.elsewhen
您将意识到,它很快就会变得冗长,实用程序.otherwise
提供了更简洁的语法,用于通过一系列元组生成相同的事物。:
关于参数化使用参数的方式可能比直接定义全局对象要好,直接对
switch
s /is
s进行参数化处理会更好。例如,您可能有一个抽象的
when (io.aluop_i === EXE_OR_OP) { logicout := logicout }.otherwise { logicout := 0.U }
类,用于定义所有参数化。然后,您可以为不同版本的CPU提供具体的实现。然后,您可以在构建模块时将其传递给模块,并使用所需的模块。
然后您将MuxLookup
对象与模块一起传递以构造它:
logicout := MuxLookup( io.aluop_i, 0.U, Seq(EXE_OR_OP -> logicout) )
尽管传递所有参数确实很乏味,但是...使用Bundle
参数将减少键入的字符。同样,更强大的参数化方法是Rocket Chip使用的“上下文相关环境”库。参见:Module
。大多数项目都不需要这样做,但是对于涉及参数化的复杂情况,这是一种更干净的方法。