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位的整数类型,包括非标准大小(不仅仅是2的幂);

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

也可:

例子:

考虑一个模型从 示例,这是一个PID控制器。 使用以下数据类型 定点数字:

verilog model example

主算法在子系统中实现(块 Subsystem):

verilog model example subsystem

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

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

这里:

  • 'pid_fixed。工程师-模型名称;

  • 'pid_fixed_code’是生成Verilog代码的文件夹。;

  • 'subsystem_name="SubSystem"-指示从中生成代码的子系统;

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

您也可以使用"engee"传输当前打开的模型,而不是显式指定文件名。gcm()`:

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

在执行命令后 文件浏览器 file browser 7 此时将显示pid_fixed文件。v在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

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

  • 始终生成"时钟"和"复位"信号;

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

  • 当信号电平为高电平时`reset’总是同步且有效(active-high)。

核实资料

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

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

  • .jl脚本;

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

    verilog files example

Pid_fixed_subsystem_verification文件。jl包含命令管理语言中的脚本。 要获取验证模型,您需要运行此文件。 有两种方法可以做到这一点。:

作为执行脚本的结果,将创建一个模型`{model_name}_验证。恩吉。 它包括:

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

  • C功能块;

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

verilog command line example 1

简单地说,*C函数*块包含从源模型生成的Verilog代码。 多亏了这一点,你可以:

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

  • 嵌入验证模型作为原始模型的子系统并比较结果。

传统的通用处理器无法直接执行用于合成的Verilog RTL代码。 但是,这是可能的使用仿真器,如 Verilator。 该工具将Verilog代码转换为行为等效的C++代码,可以运行它来比较结果。

生成的C++代码被打包到一个包含用于控制仿真的接口的库中,辅助文件被放置在obj_dir文件夹中(前面提到过)。 然后验证模型中的*C函数*块使用这个库来工作。

如何从内部使用Verilog

advanced users cn

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

  1. 翻译成凿子-代码生成器将输入模型翻译成凿子语言代码。 Chisel是一种用于scala中内置的高级硬件描述的语言。 它提供了简化硬件设计的抽象,并允许您使用Scala功能来处理设计。;

  2. 转换为FIRRTL-Chisel暴露了高级构造并转换为FIRRTL(用于RTL的灵活中间表示)。 在这个阶段:

    1. 1. Reduce等高级方法正在被其低级等效方法所取代;

    1. 2. 定点运算转换为位运算。

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

我如何获得凿子代码?

默认情况下,在第一阶段生成的凿子代码不会保存在代码文件夹中。 但是,它可以用于调试或开发。 要获取此文件,请使用 程序控制通过将`target="chisel"`参数传递给`generate_code`命令。 例如:

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

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

verilog command line example 2

带的文件。scala扩展包含凿子代码:

凿子代码示例
//> 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模板应该主要用凿子语言创建,必要时使用Julia的内置控制结构。

有关使用自定义代码生成模板的详细信息,请参阅文章 根据自定义模板生成代码.

支持的块

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