Engee 文档

Verilog (HDL) 代码生成

除了 C-代码生成,Verilog 代码也可以从 Engee 中有限的程序块中生成。 Verilog 是一种流行的硬件描述语言(HDL),用于ASIC和FPGA的设计和测试。生成的代码可合成为网表,用于 ASIC 光刻或 FPGA 固件创建。

生成 Verilog 代码的过程与生成 C 代码类似。

  1. 设置窗口debug article icon 1 中,单击 代码生成 选项卡,在 目标平台 选项中选择 Verilog;

  2. 单击工作区左上角的 生成代码 verilog icon

  3. 文件浏览器file browser 7{model_name}_code 文件夹中,会出现一个扩展名为 .v 的文件—​生成的 Verilog 代码。

您也可以使用generate_code 函数,指定 Verilog 为目标语言。

Verilog 代码生成器的功能

支持的数据类型:

  • 宽度不超过 128 位的整数类型,包括非标准大小(不仅是二度);

  • 具有定点和正分数长度的符号类型。

还可提供

示例

请看示例 中的模型,这是一个 PID 控制器。使用的数据类型是定点数

verilog model example

基本算法在子系统(块子系统 )中实现:

verilog model example subsystem

由于算法是在子系统中实现的,因此将从中生成 Verilog 代码。为此,请在设置窗口debug article icon 1 中将 Verilog 设置为目标平台,然后在终端执行命令:

engee.generate_code("pid_fixed.engee", "pid_fixed_code", subsystem_name="SubSystem", target="verilog")

此处:

  • pid_fixed.engee - 模型名称;

  • pid_fixed_code - 生成 Verilog 代码的文件夹;

  • subsystem_name="子系统"--表示生成代码的子系统;

  • target="verilog"-指定代码生成器的语言。

您也可以使用 engee.gcm() 传递当前打开的模型,而不是明确指定文件名:

engee.generate_code(engee.gcm(), "pid_fixed_code", subsystem_name="SubSystem", target="verilog")

执行命令后,文件 pid_fixed.v 将出现在文件浏览器file browser 7 中,其中包含以下 Verilog 代码:

module pid_fixed_SubSystem(
  input         clock,
                reset,
  input  [15:0] io_setpoint,
                io_feedback,
  output [15:0] io_command
);

  reg  [15:0] UnitDelay_state;
  wire [15:0] _AddAccum_T = io_setpoint - io_feedback;
  wire [41:0] _Gain_2_new_T_3 = {{26{_AddAccum_T[15]}}, _AddAccum_T} * 42'h148000;
  wire [29:0] _Gain_new_T_1 = {{14{_AddAccum_T[15]}}, _AddAccum_T} * 30'h6000;
  wire [15:0] _Add_1Accum_T = {_Gain_2_new_T_3[41:27], 1'h0} + UnitDelay_state;
  always @(posedge clock) begin
    if (reset)
      UnitDelay_state <= 16'h0;
    else
      UnitDelay_state <= _Add_1Accum_T;
  end // always @(posedge)
  assign io_command = _Gain_new_T_1[29:14] + {_Add_1Accum_T[15], _Add_1Accum_T[15:1]};
endmodule

生成的代码具有以下特点:

  • 总是生成 "时钟 "和 "复位 "信号;

  • 同时使用顺序逻辑和组合逻辑,但不支持组合循环;

  • "复位 "总是同步和高电平有效。

验证

验证涉及使用 C 功能 块创建一个验证模型,其仿真结果应与具有相同输入数据的原始模型的结果相匹配。

与 C 代码生成一样,您可以在 "代码生成 "选项卡的设置窗口中启用 "生成 C 功能块 "选项。在这种情况下,除了 Verilog 文件(.v)外,包含生成的 Verilog 代码的文件夹还将包含以下内容:

  • .jl 脚本;

  • 包含以下辅助文件的 obj_dir 文件夹:

    verilog files example

文件 pid_fixed_Subsystem_verification.jl 包含一个命令控制语言脚本。要获取验证模型,需要执行该文件。执行方法有两种:

  • 命令行img 41 1 2 中输入`include("/path/to/file")`命令:

    verilog command line example

  • 单击 脚本编辑器interactive script icon 右上角的 "运行脚本 "按钮content button 3

    verilog script start

运行脚本后,将生成一个模型 {model_name}_verification.engee。它包括

  • 原始模型(或子系统)的输入和输出块;

  • *C 功能*块

  • 信号类型转换辅助块(如果模型使用定点类型)。

verilog command line example 1

简化后,C Function 块包含从源模型生成的 Verilog 代码。因此可以

  • 启用输出记录或在工作区中保存 仿真结果。然后 比较源模型和验证模型在相同输入数据上的仿真结果(必须匹配);

    验证指的是用 C 功能 块生成验证模型,其仿真结果必须与源模型在相同输入数据上的仿真结果相匹配。
  • 将验证模型作为源模型的子系统构建,并比较结果。

传统的通用处理器无法直接执行用于综合的 Verilog RTL 代码。不过,使用 Verilator等仿真器可以做到这一点。该工具可将 Verilog 代码转换为等效的行为 C++ 代码,运行后可对结果进行比较。

生成的 C++ 代码被打包在一个包含控制仿真界面的库中,而辅助文件则放在 obj_dir 文件夹中(如前所述)。然后,验证模型中的 C Function 块将使用该库进行操作。

Verilog 内部工作原理

advanced users cn

对于高级用户,如 HDL 代码生成的模板开发人员,了解 Verilog 生成的步骤非常重要。简化后,流程如下:

  1. 翻译为 Chisel - 代码生成器将输入模型翻译为 Chisel 语言的代码。Chisel 是一种内置于 Scala 的高级硬件描述语言。它提供了简化硬件设计的抽象,使您能够充分利用 Scala 的设计能力;

  2. 转换为 FIRRTL - Chisel 公开高级设计并转换为 FIRRTL(Flexible Intermediate Representation for RTL)。在此步骤中

  3. 转换为 Verilog - 使用 CIRCT(firtool 工具)将 FIRRTL 转换为最终的 Verilog 代码。

如何获取 Chisel 代码?

默认情况下,第一步生成的 Chisel 代码不会保存在代码文件夹中。不过,它对调试或开发很有用。要获取该文件,请使用 programmatic-management,向 generate_code 命令传递 target="chisel" 参数。例如

engee.generate_code(engee.gcm(), "pid_fixed_code", target="chisel", subsystem_name="SubSystem")

执行 Chisel 命令后,代码将保存在指定文件夹中,可用于后续工作:

verilog command line example 2

扩展名为 .scala 的文件包含 Chisel 代码:

Chisel 代码示例
//> using scala "2.13.14"
//> using dep "org.chipsalliance::chisel:6.5.0"
//> using plugin "org.chipsalliance:::chisel-plugin:6.5.0"
//> using options "-unchecked", "-deprecation", "-feature", "-language:reflectiveCalls", "-Xcheckinit", "-Xfatal-warnings", "-Wdead-code"

import chisel3._
import circt.stage.ChiselStage
import fixedpoint._

class pid_fixed_SubSystem extends Module {
	val io = IO(new Bundle{
		val setpoint = Input(FixedPoint(16.W,14.BP)) /* /setpoint */
		val feedback = Input(FixedPoint(16.W,14.BP)) /* /feedback */
		val command = Output(FixedPoint(16.W,13.BP)) /* /command */
	})
	val Add = Wire(FixedPoint(16.W,14.BP))
	val AddAccum = Wire(FixedPoint(16.W,14.BP))
	val AddCast0iosetpoint = Wire(FixedPoint(16.W,14.BP))
	val AddCast1iofeedback = Wire(FixedPoint(16.W,14.BP))
	val UnitDelay = Wire(FixedPoint(16.W,14.BP))
	val Gain_2 = Wire(FixedPoint(16.W,13.BP))
	val Gain = Wire(FixedPoint(16.W,13.BP))
	val Add_1 = Wire(FixedPoint(16.W,14.BP))
	val Add_1Accum = Wire(FixedPoint(16.W,14.BP))
	val Add_1Cast0Gain_2 = Wire(FixedPoint(16.W,14.BP))
	val Add_1Cast1UnitDelay = Wire(FixedPoint(16.W,14.BP))
	val Add_2 = Wire(FixedPoint(16.W,13.BP))
	val Add_2Accum = Wire(FixedPoint(16.W,13.BP))
	val Add_2Cast0Gain = Wire(FixedPoint(16.W,13.BP))
	val Add_2Cast1Add_1 = Wire(FixedPoint(16.W,13.BP))
	val UnitDelay_state = RegInit({ val _init = Wire(FixedPoint(16.W,14.BP)); _init := 0.0.F(16.W,14.BP); _init })

	/* Output for UnitDelay: /Unit Delay */
	UnitDelay := UnitDelay_state
	/* Sum: /Add incorporates:
	 *  Inport: /setpoint
	 *  Inport: /feedback
	 */
	AddCast0iosetpoint := io.setpoint
	AddCast1iofeedback := io.feedback
	AddAccum := AddCast0iosetpoint - AddCast1iofeedback
	Add := AddAccum
	/* Gain: /Gain-2 incorporates:
	 *  Sum: /Add
	 */
	Gain_2 := 0.02.F(16.W,13.BP) * Add
	/* Gain: /Gain incorporates:
	 *  Sum: /Add
	 */
	Gain := 3.0.F(16.W,13.BP) * Add
	/* Sum: /Add-1 incorporates:
	 *  Gain: /Gain-2
	 *  UnitDelay: /Unit Delay
	 */
	Add_1Cast0Gain_2 := Gain_2
	Add_1Cast1UnitDelay := UnitDelay
	Add_1Accum := Add_1Cast0Gain_2 + Add_1Cast1UnitDelay
	Add_1 := Add_1Accum
	/* Sum: /Add-2 incorporates:
	 *  Gain: /Gain
	 *  Sum: /Add-1
	 */
	Add_2Cast0Gain := Gain
	Add_2Cast1Add_1 := Add_1
	Add_2Accum := Add_2Cast0Gain + Add_2Cast1Add_1
	Add_2 := Add_2Accum
	/* Outport: /command incorporates:
	 *  Sum: /Add-2
	 */
	io.command := Add_2
	/* Update for UnitDelay: /Unit Delay */
	UnitDelay_state := Add_1

}


object pid_fixed_SubSystemDriver extends App {
	ChiselStage.emitSystemVerilogFile(
		new pid_fixed_SubSystem,
		firtoolOpts = Array("--disable-all-randomization", "--strip-debug-info",
		                    "--lowering-options=disallowLocalVariables"))
}
只有选择 Verilog 作为目标平台,才能运行 .jl 脚本生成的验证模型。如果未生成 obj_dir 文件夹,验证模型将无法运行。

代码模板在第一步生成时就已暴露,因此 HDL 模板的创建应主要在 Chisel 中完成,必要时使用 Julia 的内置控制结构。

支持的块

Engee* 代码生成器支持以下库块的 HDL 生成: