## 举例(Example) ### 一、外部断言(External assertions) 这是一个简单计数器和其对应形式化验证的例子: ```Scala import spinal.core._ //Here is our DUT class LimitedCounter extends Component{ //The value register will always be between [2:10] val value = Reg(UInt(4 bits)) init(2) when(value < 10){ value := value + 1 } } object LimitedCounterFormal extends App { // import utilities to run the formal verification, but also some utilities to describe formal stuff import spinal.core.formal._ // Here we run a formal verification which will explore the state space up to 15 cycles to find an assertion failure FormalConfig.withBMC(15).doVerify(new Component { // Instanciate our LimitedCounter DUT as a FormalDut, which ensure that all the outputs of the dut are: // - directly and indirectly driven (no latch / no floating wire) // - allows the current toplevel to read every signal across the hierarchy val dut = FormalDut(new LimitedCounter()) // Ensure that the state space start with a proper reset assumeInitial(ClockDomain.current.isResetActive) // Check a few things assert(dut.value >= 2) assert(dut.value <= 10) }) } Internal assertions If you want you can embed formal statements directly into the DUT: class LimitedCounterEmbedded extends Component{ val value = Reg(UInt(4 bits)) init(2) when(value < 10){ value := value + 1 } // That code block will not be in the SpinalVerilog netlist by default. (would need to enable SpinalConfig().includeFormal. ... GenerationFlags.formal { assert(value >= 2) assert(value <= 10) } } object LimitedCounterEmbeddedFormal extends App { import spinal.core.formal._ FormalConfig.withBMC(15).doVerify(new Component { val dut = FormalDut(new LimitedCounterEmbedded()) assumeInitial(ClockDomain.current.isResetActive) }) } ``` ### 二、内部断言(Internal assertions) 如果你愿意你也可以把形式化语句直接包含在DUT中: ```Scala class LimitedCounterEmbedded extends Component{ val value = Reg(UInt(4 bits)) init(2) when(value < 10){ value := value + 1 } // That code block will not be in the SpinalVerilog netlist by default. (would need to enable SpinalConfig().includeFormal. ... GenerationFlags.formal { assert(value >= 2) assert(value <= 10) } } object LimitedCounterEmbeddedFormal extends App { import spinal.core.formal._ FormalConfig.withBMC(15).doVerify(new Component { val dut = FormalDut(new LimitedCounterEmbedded()) assumeInitial(ClockDomain.current.isResetActive) }) } ``` ### 三、外部激励(External stimulus) 如果你的DUT有输入, 你需要从testbench中驱动他们。所有的一般硬件语句都可以实现它, 但是你也可以用形式化*anyseq*,*qnyconst*, *allseq*, *allconst*语句: ```Scala class LimitedCounterInc extends Component{ //Only increment the value when the inc input is set val inc = in Bool() val value = Reg(UInt(4 bits)) init(2) when(inc && value < 10){ value := value + 1 } } object LimitedCounterIncFormal extends App { import spinal.core.formal._ FormalConfig.withBMC(15).doVerify(new Component { val dut = FormalDut(new LimitedCounterInc()) assumeInitial(ClockDomain.current.isResetActive) assert(dut.value >= 2) assert(dut.value <= 10) // Drive dut.inc with random values anyseq(dut.inc) }) } ``` ### 四、更多的断言/传递(More assertions/past) 例如我们可以检查值是否计数自增(如果没到10): ```Scala FormalConfig.withBMC(15).doVerify(new Component { val dut = FormalDut(new LimitedCounter()) assumeInitial(ClockDomain.current.isResetActive) // Check that the value is incrementing. // hasPast is used to ensure that the past(dut.value) had at least one sampling out of reset when(pastValid() && past(dut.value) =/= 10){ assert(dut.value === past(dut.value) + 1) } }) ``` ### 五、假设存储内容(Assuming memory content) 本例中我们希望防止`1`出现在内存中: ```Scala class DutWithRam extends Component{ val ram = Mem.fill(4)(UInt(8 bits)) val write = slave(ram.writePort) val read = slave(ram.readAsyncPort) } object FormalRam extends App { import spinal.core.formal._ FormalConfig.withBMC(15).doVerify(new Component { val dut = FormalDut(new DutWithRam()) assumeInitial(ClockDomain.current.isResetActive) // assume that no word in the ram has the value 1 for(i <- 0 until dut.ram.wordCount){ assumeInitial(dut.ram(i) =/= 1) } // Allow the write anything but value 1 in the ram anyseq(dut.write) clockDomain.withoutReset(){ //As the memory write can occur during reset, we need to ensure the assume apply there too assume(dut.write.data =/= 1) } // Check that no word in the ram is set to 1 anyseq(dut.read.address) assert(dut.read.data =/= 1) }) } ```