You're reading an pre-release version of this documentation.
For the latest stable release version, please have a look at master.

VHDL 和 Verilog 生成

从 SpinalHDL 组件生成 VHDL 和 Verilog

要从 SpinalHDL 组件生成 VHDL,您只需在 Scala main 函数中调用 SpinalVhdl(new YourComponent) 即可。

生成 Verilog 完全相同,但用 SpinalVerilog 代替 SpinalVHDL

import spinal.core._

// A simple component definition.
class MyTopLevel extends Component {
  // Define some input/output signals. Bundle like a VHDL record or a Verilog struct.
  val io = new Bundle {
    val a = in  Bool()
    val b = in  Bool()
    val c = out Bool()
  }

  // Define some asynchronous logic.
  io.c := io.a & io.b
}

// This is the main function that generates the VHDL and the Verilog
// corresponding to MyTopLevel.
object MyMain {
  def main(args: Array[String]) {
    SpinalVhdl(new MyTopLevel)
    SpinalVerilog(new MyTopLevel)
  }
}

重要

SpinalVhdlSpinalVerilog 可能需要创建组件类的多个实例,因此第一个参数不是 Component 引用,而是返回新组件的函数。

重要

SpinalVerilog 实施于 2016 年 6 月 5 日开始。该后端成功通过了与 VHDL 相同的回归测试(RISCV CPU、多核和流水线 Mandelbrot、UART RX/TX、单时钟域 fifo、双时钟域 fifo、格雷码计数器, …)。

如果您对这个新后端有任何问题,请创建 Github 工单 描述问题。

Scala 的参数化

参数名称

类型

默认值

描述

mode

SpinalMode

null

设置 SpinalHDL 生成HDL的模式。
可以设置为 VHDLVerilog

defaultConfigForClockDomains

ClockDomainConfig

RisingEdgeClock
AsynchronousReset
ResetActiveHigh
ClockEnableActiveHigh

设置将用作所有新 ``ClockDomain``时钟域默认值的配置。

onlyStdLogicVectorAtTopLevelIo

Boolean

false

将所有无符号/有符号顶级 io 更改为 std_logic_vector类型。

defaultClockDomainFrequency

IClockDomainFrequency

 UnknownFrequency

默认时钟频率。

targetDirectory

String

当前目录

生成文件的目录。

oneFilePerComponent

Boolean

false

没有该选项时,SpinalHDL生成一个囊括所有组件的顶层文件。使用该选项则会为每个组件分别生成一个文件。

netlistFileName

String

顶层类名.(vhd|v)

允许更改生成的 VHDL/Verilog 文件名。

globalPrefix

String

“”

在 VHDL/Verilog 中所有全局符号(组件/模块/枚举)前添加指定前缀。这有助于避免多个生成文件之间的命名冲突。

privateNamespace

Boolean

false

所有生成的组件/模块名称(顶层除外)都将以顶层组件/模块名为前缀。这有助于避免多个生成文件之间的命名冲突。

formalAsserts

Boolean

false

启用 VHDL/Verilog 中形式化断言的生成。

anonymSignalPrefix

String

“zz_”

设置添加到未命名信号的前缀。

inlineRom

Boolean

false

配置 Verilog 后端,将 ROM 初始化值内嵌于 Verilog 代码中,而非生成独立的二进制文件。

caseRom

Boolean

false

以大型 switch case 语句形式生成 ROM。

mergeAsyncProcess

Boolean

false

合并至少共享一个条件赋值(if/switch 语句)的组合逻辑信号的 process/always 块。

mergeSyncProcess

Boolean

true

合并使用相同时钟域的触发器(flip-flop)的 process/always 块(if/switch 语句)。

genLineComments

Boolean

false

为生成的 VHDL/Verilog 代码中的每项硬件赋值附加注释,标明该赋值所在的 Scala 文件及行号。例如:a = 1’b1; // @ MyDesign.scala l1135

noAssert

Boolean

false

从生成的代码中移除所有断言

headerWithDate

Boolean

false

在生成的 VHDL/Verilog 文件头中添加生成日期。

headerWithRepoHash

Boolean

true

在生成的 VHDL/Verilog 文件头中添加当前目录的 Git 哈希值。

dontCareGenAsZero

Boolean

false

将 mySignal.assignDontCare() 替换为 mySignal := 0

obfuscateNames

Boolean

false

混淆生成的组件名与信号名。

rtlHeader

String

disabled

允许手动指定 VHDL/Verilog 文件头

withTimescale

Boolean

True

在生成的 Verilog 代码中添加时间尺度(timescale)

normalizeComponentClockDomainName

Boolean

False

启用后,在每个组件中,隐式时钟域所引出的时钟域信号将被命名为 clk/reset/enable,而非其原始名称。

这是设置它们的语法:

SpinalConfig(mode=VHDL, targetDirectory="temp/myDesign").generate(new UartCtrl)

// Or for Verilog in a more scalable formatting:
SpinalConfig(
  mode=Verilog,
  targetDirectory="temp/myDesign"
).generate(new UartCtrl)

来自 shell 的参数化

您还可以使用命令行参数指定生成参数。

def main(args: Array[String]): Unit = {
  SpinalConfig.shell(args)(new UartCtrl)
}

命令行参数的语法是:

Usage: SpinalCore [options]

  --vhdl
        Select the VHDL mode
  --verilog
        Select the Verilog mode
  -o <value> | --targetDirectory <value>
        Set the target directory

生成的 VHDL 和 Verilog

如何将 SpinalHDL RTL 描述转换为 VHDL 和 Verilog 非常重要:

  • Scala 中变量的名称将保留在 VHDL 和 Verilog 中。

  • Scala 中的 Component 组件层次结构会保留在 VHDL 和 Verilog 中。

  • Scala 中的 when 语句会生成为 VHDL 和 Verilog 中的 if 语句。

  • Scala 中的 switch 语句在所有标准情况下都生成为 VHDL 和 Verilog 中的 case 语句。

组织

当您使用 VHDL 生成器时,所有模块都会生成到一个文件中,其中包含三个部分:

  1. 包含所有 Enum 定义的包

  2. 包含架构中所有元素使用函数的包

  3. 您的设计所需的所有组件

当您使用 Verilog 生成时,所有模块都会生成到一个文件中,其中包含两个部分:

  1. 使用的所有枚举定义

  2. 您的设计需要的所有模块

组合逻辑

Scala:

class TopLevel extends Component {
  val io = new Bundle {
    val cond           = in  Bool()
    val value          = in  UInt(4 bits)
    val withoutProcess = out UInt(4 bits)
    val withProcess    = out UInt(4 bits)
  }
  io.withoutProcess := io.value
  io.withProcess := 0
  when(io.cond) {
    switch(io.value) {
      is(U"0000") {
        io.withProcess := 8
      }
      is(U"0001") {
        io.withProcess := 9
      }
      default {
        io.withProcess := io.value+1
      }
    }
  }
}

VHDL:

entity TopLevel is
  port(
    io_cond : in std_logic;
    io_value : in unsigned(3 downto 0);
    io_withoutProcess : out unsigned(3 downto 0);
    io_withProcess : out unsigned(3 downto 0)
  );
end TopLevel;

architecture arch of TopLevel is
begin
  io_withoutProcess <= io_value;
  process(io_cond,io_value)
  begin
    io_withProcess <= pkg_unsigned("0000");
    if io_cond = '1' then
      case io_value is
        when pkg_unsigned("0000") =>
          io_withProcess <= pkg_unsigned("1000");
        when pkg_unsigned("0001") =>
          io_withProcess <= pkg_unsigned("1001");
        when others =>
          io_withProcess <= (io_value + pkg_unsigned("0001"));
      end case;
    end if;
  end process;
end arch;

时序逻辑

Scala:

class TopLevel extends Component {
  val io = new Bundle {
    val cond   = in Bool()
    val value  = in UInt (4 bits)
    val resultA = out UInt(4 bits)
    val resultB = out UInt(4 bits)
  }

  val regWithReset = Reg(UInt(4 bits)) init(0)
  val regWithoutReset = Reg(UInt(4 bits))

  regWithReset := io.value
  regWithoutReset := 0
  when(io.cond) {
    regWithoutReset := io.value
  }

  io.resultA := regWithReset
  io.resultB := regWithoutReset
}

VHDL:

entity TopLevel is
  port(
    io_cond : in std_logic;
    io_value : in unsigned(3 downto 0);
    io_resultA : out unsigned(3 downto 0);
    io_resultB : out unsigned(3 downto 0);
    clk : in std_logic;
    reset : in std_logic
  );
end TopLevel;

architecture arch of TopLevel is

  signal regWithReset : unsigned(3 downto 0);
  signal regWithoutReset : unsigned(3 downto 0);
begin
  io_resultA <= regWithReset;
  io_resultB <= regWithoutReset;
  process(clk,reset)
  begin
    if reset = '1' then
      regWithReset <= pkg_unsigned("0000");
    elsif rising_edge(clk) then
      regWithReset <= io_value;
    end if;
  end process;

  process(clk)
  begin
    if rising_edge(clk) then
      regWithoutReset <= pkg_unsigned("0000");
      if io_cond = '1' then
        regWithoutReset <= io_value;
      end if;
    end if;
  end process;
end arch;

VHDL 和 Verilog 属性

在某些情况下,为设计中的某些信号提供属性以修改它们的综合方式很有用。

为此,您可以对设计中的任何信号或存储器调用以下函数:

语法

描述

addAttribute(name)

添加一个名为 name 的布尔属性,并将给定值设置为 true

addAttribute(name, value)

添加一个字符串属性,并将给定的 name 设置为 value

示例:

val pcPlus4 = pc + 4
pcPlus4.addAttribute("keep")

用 VHDL 生成声明:

attribute keep : boolean;
signal pcPlus4 : unsigned(31 downto 0);
attribute keep of pcPlus4: signal is true;

用 Verilog 生成声明:

(* keep *) wire [31:0] pcPlus4;