【SpinalHDL快速入门】2、新建SpinalHDL工程,通过计数器Demo快速上手

本文介绍了如何配置新建工程的工具版本,如JDK、Scala和Sbt,以及SpinalHDL的使用。提供了`build.sbt`和`build.properties`的示例,并展示了在IDEA中更新SpinalVersion和Reloadsbt项目的方法。此外,通过三个逐步进阶的SpinalHDL计数器demo,详细讲解了异步复位功能的实现,包括Verilog代码生成和模拟测试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

新建工程

各个工具版本

配置文件主要是:build.sbtbuild.properties

  • JDK:1.8
  • scala:2.11.12
  • sbt:1.5.5
  • spinal:1.6.0 / 1.6.1(加入Enum)/ 1.8.1

在这里插入图片描述

build.sbt 示例

常见写法参考:

ThisBuild / version := "0.1.0-SNAPSHOT"

ThisBuild / scalaVersion := "2.11.12"

val spinalVersion = "1.6.0"
val spinalCore = "com.github.spinalhdl" %% "spinalhdl-core" % spinalVersion
val spinalLib = "com.github.spinalhdl" %% "spinalhdl-lib" % spinalVersion
val spinalIdslPlugin = compilerPlugin("com.github.spinalhdl" %% "spinalhdl-idsl-plugin" % spinalVersion)
lazy val root = (project in file("."))
  .settings(
    name := "scala_test",
    //    Compile / scalaSource := baseDirectory.value / "hw" / "spinal", //scala源文件不是在`src/main/scala`下,可以参考如下写法更改路径
    libraryDependencies ++= Seq(spinalCore, spinalLib, spinalIdslPlugin)
  )

fork := true

build.properties 示例

sbt.version = 1.5.5

如何在IEDA中更新 SpinalVersion 并 Reload sbt Project

在这里插入图片描述

SpinalHDL入门例子:计数器

demo1

最后生成的波形文件是test.vcd,gtkwave可以打开!

MyTopLevel.scala

package mylib

import spinal.core._
import spinal.lib._

import scala.util.Random

//Hardware definition
class MyTopLevel extends Component {
  val io = new Bundle {
    val cond0 = in  Bool()
    val cond1 = in  Bool()
    val flag  = out Bool()
    val state = out UInt(8 bits)
  }
  val counter = Reg(UInt(8 bits)) init(0)

  when(io.cond0){
    counter := counter + 1
  }

  io.state := counter
  io.flag  := (counter === 0) | io.cond1
}

//Generate the MyTopLevel's Verilog
object MyTopLevelVerilog {
  def main(args: Array[String]) {
    SpinalVerilog(new MyTopLevel)
  }
}

//Generate the MyTopLevel's VHDL
//object MyTopLevelVhdl {
//  def main(args: Array[String]) {
//    SpinalVhdl(new MyTopLevel)
//  }
//}


//Define a custom SpinalHDL configuration with synchronous reset instead of the default asynchronous one. This configuration can be resued everywhere
//定义一个自定义的SpinalHDL配置,使用同步复位而不是默认的异步复位。这个配置可以在任何地方重用。
object MySpinalConfig extends SpinalConfig(defaultConfigForClockDomains = ClockDomainConfig(resetKind = SYNC))

//Generate the MyTopLevel's Verilog using the above custom configuration.
//使用上述自定义配置生成MyTopLevel的Verilog。
object MyTopLevelVerilogWithCustomConfig {
  def main(args: Array[String]) {
    MySpinalConfig.generateVerilog(new MyTopLevel)
  }
}

对应生成的Verilog代码

// Generator : SpinalHDL v1.6.0    git head : 73c8d8e2b86b45646e9d0b2e729291f2b65e6be3
// Component : MyTopLevel



module MyTopLevel (
  input               io_cond0,
  input               io_cond1,
  output              io_flag,
  output     [7:0]    io_state,
  input               clk,
  input               reset
);
  reg        [7:0]    counter;

  assign io_state = counter;
  assign io_flag = ((counter == 8'h0) || io_cond1);
  always @(posedge clk or posedge reset) begin
    if(reset) begin
      counter <= 8'h0;
    end else begin
      if(io_cond0) begin
        counter <= (counter + 8'h01);
      end
    end
  end


endmodule

MyTopLevelSim

package mylib

import spinal.core._
import spinal.sim._
import spinal.core.sim._

import scala.util.Random


//MyTopLevel's testbench
object MyTopLevelSim {
  def main(args: Array[String]) {
    SimConfig.withWave.doSim(new MyTopLevel){dut =>
      //Fork a process to generate the reset and the clock on the dut
      dut.clockDomain.forkStimulus(period = 10)

      var modelState = 0
      for(idx <- 0 to 99){
        //Drive the dut inputs with random values
        dut.io.cond0 #= Random.nextBoolean()
        dut.io.cond1 #= Random.nextBoolean()

        //Wait a rising edge on the clock
        dut.clockDomain.waitRisingEdge()

        //Check that the dut values match with the reference model ones
        val modelFlag = modelState == 0 || dut.io.cond1.toBoolean
        assert(dut.io.state.toInt == modelState)
        assert(dut.io.flag.toBoolean == modelFlag)

        //Update the reference model value
        if(dut.io.cond0.toBoolean) {
          modelState = (modelState + 1) & 0xFF
        }
      }
    }
  }
}

demo2(支持reset信号异步复位,低电平有效)

最后生成的波形文件是test.fst,gtkwave也是也可以打开的!

Config.scala

package projectname

import spinal.core._
import spinal.core.sim._

object Config {
  def spinal = SpinalConfig(
//    targetDirectory = "hw/gen",
    defaultConfigForClockDomains = ClockDomainConfig(
//      resetActiveLevel = HIGH
      //异步复位
      clockEdge = RISING,
      resetKind = ASYNC,
      resetActiveLevel = LOW
    ),
    onlyStdLogicVectorAtTopLevelIo = true
  )

  def sim = SimConfig.withConfig(spinal).withFstWave
}

MyTopLevel.scala

package projectname

import spinal.core._

// Hardware definition
case class MyTopLevel() extends Component {
  val io = new Bundle {
    val cond0 = in  Bool()
    val cond1 = in  Bool()
    val flag  = out Bool()
    val state = out UInt(8 bits)
  }

  val counter = Reg(UInt(8 bits)) init 0

  when(io.cond0) {
    counter := counter + 1
  }

  io.state := counter
  io.flag := (counter === 0) | io.cond1
}

//main函数就在App这个类中!
object MyTopLevelVerilog extends App {
  Config.spinal.generateVerilog(MyTopLevel())
}

//object MyTopLevelVhdl extends App {
//  Config.spinal.generateVhdl(MyTopLevel())
//}

生成的Verilog代码如下:

// Generator : SpinalHDL v1.6.0    git head : 73c8d8e2b86b45646e9d0b2e729291f2b65e6be3
// Component : MyTopLevel



module MyTopLevel (
  input               io_cond0,
  input               io_cond1,
  output              io_flag,
  output     [7:0]    io_state,
  input               clk,
  input               resetn
);
  reg        [7:0]    counter;

  assign io_state = counter;
  assign io_flag = ((counter == 8'h0) || io_cond1);
  always @(posedge clk or negedge resetn) begin
    if(!resetn) begin
      counter <= 8'h0;
    end else begin
      if(io_cond0) begin
        counter <= (counter + 8'h01);
      end
    end
  end


endmodule

MyTopLevelSim.scala

package projectname

import spinal.core._
import spinal.core.sim._

object MyTopLevelSim extends App {
  Config.sim.compile(MyTopLevel()).doSim { dut =>
    // Fork a process to generate the reset and the clock on the dut
    dut.clockDomain.forkStimulus(period = 10)

    var modelState = 0
    for (idx <- 0 to 99) {
      // Drive the dut inputs with random values
      dut.io.cond0.randomize()
      dut.io.cond1.randomize()

      // Wait a rising edge on the clock
      dut.clockDomain.waitRisingEdge()

      // Check that the dut values match with the reference model ones
      val modelFlag = modelState == 0 || dut.io.cond1.toBoolean
      assert(dut.io.state.toInt == modelState)
      assert(dut.io.flag.toBoolean == modelFlag)

      // Update the reference model value
      if (dut.io.cond0.toBoolean) {
        modelState = (modelState + 1) & 0xff
      }
    }
  }
}

demo3(一个文件,支持异步复位)【个人常用这个】

package test

import spinal.core._
import spinal.lib._


case class MyTopLevel() extends Component {
  val io = new Bundle {
    val cond0 = in  Bool()
    val cond1 = in  Bool()
    val flag  = out Bool()
    val state = out UInt(8 bits)
  }
  val counter = Reg(UInt(8 bits)) init(0)

  when(io.cond0){
    counter := counter + 1
  }

  io.state := counter
  io.flag  := (counter === 0) | io.cond1
}


object MyTopLevelApp extends App{
  SpinalConfig(
  	//异步复位
    defaultConfigForClockDomains = ClockDomainConfig(
      clockEdge = RISING,
      resetKind = ASYNC,
      resetActiveLevel = LOW
    ),
    //defaultClockDomainFrequency = FixedFrequency(100 MHz),
    targetDirectory = "rtl" //生成的Verilog放到rtl目录下
  ).generateVerilog(MyTopLevel()).printPruned() //generateSystemVerilog也是可以的
}

Scala 基础

饱和运算

《SpinalHDL_docs》P53

x +| y 饱和加法运算 T(max(w(x), w(y)) bits)
x -| y 饱和减法运算 T(max(w(x), w(y)) bits)
val e = a +| U"8’x20"
assert(e === U"8’xff") //结果是最大值255.

计数器Demo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ReCclay

如果觉得不错,不妨请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值