Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test bench needs INLINE when passing down top entity #2196

Open
DigitalBrains1 opened this issue May 8, 2022 · 1 comment
Open

Test bench needs INLINE when passing down top entity #2196

DigitalBrains1 opened this issue May 8, 2022 · 1 comment

Comments

@DigitalBrains1
Copy link
Member

Normally, when a function recognised as a test bench makes use of a function recognised as a top entity, these two end up in separate directories (and VHDL libraries). However, when testBench passes the topEntity down to a called function, a new design unit inside the test bench output directory is created with a name based on topEntity, and testBench no longer uses the separate topEntity.

This code:

module TBInline where

import Clash.Explicit.Prelude
import Clash.Explicit.Testbench

topEntity ::
  Unsigned 8 ->
  Unsigned 8
topEntity = id
{-# NOINLINE topEntity #-}

tb0 ::
  ( Unsigned 8 ->
    Unsigned 8
  ) ->
  Signal System Bool
tb0 top = done
 where
  testInput = stimuliGenerator clk rst $(listToVecTH [0 :: Unsigned 8 .. 10])
  expectedOutput = outputVerifier' clk rst
                                   $(listToVecTH [0 :: Unsigned 8 .. 10])
  done = expectedOutput (top <$> testInput)
  clk = tbClockGen (not <$> done)
  rst = resetGen

testBench
  :: Signal System Bool
testBench = tb0 topEntity
{-# NOINLINE testBench #-}

gives the following directory structure:

$ ls -R vhdl
vhdl/:
TBInline.testBench  TBInline.topEntity

vhdl/TBInline.testBench:
clash-manifest.json                         testBench.vhdl
TBInline_testBench_types.vhdl               topEntity_0.vhdl
testBench_slv2string_2F58399B7F4E729C.vhdl

vhdl/TBInline.topEntity:
clash-manifest.json  TBInline_topEntity_types.vhdl  topEntity.vhdl

and testBench.vhdl only refers to vhdl/TBInline.testBench/topEntity_0.vhdl, there is no reference to vhdl/TBInline.topEntity/topEntity.vhdl.

topEntity_0.vhdl actually contains tb0, not just topEntity.

Adding INLINE on tb0 fixes the issue.

A certain minimum amount of complexity inside tb0 is needed to prevent automatic inlining, so I just wrote a bog-standard test bench to pass that bar.

The exact same thing happens when, instead of using functions named testBench and topEntity, we use functions with a defSyn and a TestBench annotation; it is not related to the magic names themselves.

@DigitalBrains1
Copy link
Member Author

Note that there is a functional difference. The following code:

Click to expand code block
module TBInline where

import Clash.Explicit.Prelude
import Clash.Explicit.Testbench

type Top =
  Clock System ->
  Reset System ->
  Enable System ->
  Signal System (Unsigned 8) ->
  Signal System (Unsigned 8)

myReg :: Top
myReg clk rst en = register clk rst en 0
{-# NOINLINE myReg #-}

top :: Top
top = myReg
{-# NOINLINE top #-}
{-# ANN top (defSyn "top") #-}

tb0 ::
  Top ->
  Signal System Bool
tb0 top0 = done
 where
  testInput = stimuliGenerator clk rst $(listToVecTH [1 :: Unsigned 8 .. 10])
  expectedOutput = outputVerifier' clk rst
                                   $(listToVecTH [0 :: Unsigned 8 .. 10])
  done = expectedOutput (top0 clk rst en testInput)
  clk = tbClockGen (not <$> done)
  rst = resetGen
  en = enableGen

tb ::
  Signal System Bool
tb = tb0 top
{-# NOINLINE tb #-}
{-# ANN tb (TestBench 'top) #-}

will exercise the register primitive with ~ISACTIVEENABLE evaluating false because the enableGen is visible from myReg. But adding INLINE to tb0 so it uses the actual top entity will have ~ISACTIVEENABLE evaluate true because it is a proper enable line in that configuration. So the test bench exercises a different primitive code path than usual due to this issue.

(Note I chose annotations instead of special names in this variant just to have an example of that too).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant