Skip to content

Commit fdf0667

Browse files
committed
Add simple Hedgehog generator support
1 parent f34e4f1 commit fdf0667

File tree

6 files changed

+67
-11
lines changed

6 files changed

+67
-11
lines changed

clash-testbench/clash-testbench.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ library
3939
Clash.Testbench.Input
4040
Clash.Testbench.Output
4141
Clash.Testbench.Simulate
42+
Clash.Testbench.Generate
4243
other-modules:
4344
Clash.Testbench.Internal.ID
4445
Clash.Testbench.Internal.Signal
@@ -48,6 +49,7 @@ library
4849
base,
4950
mtl,
5051
array,
52+
hedgehog,
5153
containers,
5254
bytestring,
5355
clash-ffi,

clash-testbench/src/Clash/Testbench.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ module Clash.Testbench
1010
, module Clash.Testbench.Input
1111
, module Clash.Testbench.Output
1212
, module Clash.Testbench.Simulate
13+
, module Clash.Testbench.Generate
1314
) where
1415

1516
import Clash.Testbench.Signal
1617
import Clash.Testbench.Input
1718
import Clash.Testbench.Output
1819
import Clash.Testbench.Simulate
20+
import Clash.Testbench.Generate
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module Clash.Testbench.Generate where
2+
3+
import Hedgehog
4+
import Hedgehog.Gen
5+
6+
import Clash.Prelude (KnownDomain(..), BitPack(..), NFDataX)
7+
8+
import Clash.Testbench.Signal
9+
import Clash.Testbench.Internal.ID
10+
import Clash.Testbench.Internal.Signal hiding (TBSignal, TBClock, TBReset, TBEnable)
11+
import Clash.Testbench.Internal.Monad
12+
13+
generate ::
14+
(NFDataX a, BitPack a, KnownDomain dom) =>
15+
Gen a -> TB (TBSignal dom a)
16+
generate generator =
17+
mindSignal Generator
18+
{ signalId = NoID
19+
, signalCurVal = sample generator
20+
, signalPrint = Nothing
21+
, ..
22+
}
23+
24+

clash-testbench/src/Clash/Testbench/Internal/Monad.hs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,15 @@ runTB mode testbench = do
247247
, ..
248248
} :: Internal.TBSignal 'FINAL dom a
249249
)
250+
(Generator{..} :: TBSignal dom a) ->
251+
return $ SomeSignal
252+
( Generator
253+
{ signalId = case signalId of
254+
NoID -> NoID
255+
SignalID x -> SignalID x
256+
, ..
257+
} :: Internal.TBSignal 'FINAL dom a
258+
)
250259
Internal.TBSignal{..} -> do
251260
deps <- mapM fixAutoDomIds signalDeps
252261
return $ SomeSignal $ Internal.TBSignal
@@ -257,6 +266,8 @@ runTB mode testbench = do
257266
, ..
258267
}
259268

269+
270+
260271
FreeID n <- gets idCount
261272
let a :: A.Array Int (SomeSignal 'FINAL)
262273
a = A.array (0, n-1)

clash-testbench/src/Clash/Testbench/Internal/Signal.hs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import Clash.Prelude
88
, ssymbolToString
99
)
1010

11+
import Hedgehog (Gen)
12+
1113
import Clash.FFI.VPI.Module (Module)
1214
import Clash.FFI.VPI.Port (Port, Direction)
1315

@@ -46,6 +48,12 @@ data TBSignal (s :: Stage) (dom :: Domain) a =
4648
, signalCurVal :: IO a
4749
, signalPrint :: Maybe (a -> String)
4850
}
51+
| Generator
52+
{ signalId :: ID s SIGNAL
53+
, signalCurVal :: IO a
54+
, signalPrint :: Maybe (a -> String)
55+
, generator :: Gen a
56+
}
4957

5058
instance (KnownDomain dom, AnyStage s) => Show (TBSignal s dom a) where
5159
show = case knownDomain @dom of
@@ -58,6 +66,8 @@ instance (KnownDomain dom, AnyStage s) => Show (TBSignal s dom a) where
5866
<> show signalDeps
5967
IOInput{..} ->
6068
"Input " <> show signalId
69+
Generator{..} ->
70+
"Gen " <> show signalId
6171

6272
instance AnyStage s => Eq (TBSignal s dom a) where
6373
(==) = (==) `on` signalId
@@ -79,20 +89,24 @@ instance Functor (TBSignal 'USER dom) where
7989
, signalUpdate = Nothing
8090
-- we lose printing abilities at this point. This is fine,
8191
-- since printing capabilities are recovered automatically
82-
-- once the new signal gets watched.
92+
-- once the new signal requires printing capabilities again.
8393
, signalPrint = Nothing
8494
, ..
8595
}
8696
IOInput{..} ->
8797
IOInput
8898
{ signalId = NoID
8999
, signalCurVal = f <$> signalCurVal
90-
-- we lose printing abilities at this point. This is fine,
91-
-- since printing capabilities are recovered automatically
92-
-- once the new signal gets watched.
93100
, signalPrint = Nothing
94101
, ..
95102
}
103+
Generator{..} ->
104+
Generator
105+
{ signalId = NoID
106+
, signalCurVal = f <$> signalCurVal
107+
, signalPrint = Nothing
108+
, generator = f <$> generator
109+
}
96110

97111
instance Applicative (TBSignal 'USER dom) where
98112
pure x =

clash-testbench/src/Clash/Testbench/Simulate.hs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,9 @@ simulate steps testbench = do
6767
when (i > 0) $ case signalPrint s of
6868
Nothing -> return ()
6969
Just toStr -> Prelude.putStrLn . (<> toStr v) $ case s of
70-
IOInput{} -> "I "
71-
TBSignal{} -> "O "
70+
IOInput{} -> "I "
71+
Generator{} -> "I "
72+
TBSignal{} -> "O "
7273
modifyIORef tbSimStepRef (+ 1)
7374
return r
7475

@@ -167,8 +168,9 @@ assignInputs = do
167168
-- putStrLn $ "assignInputs " <> show (time, vpiClock, vpiInit)
168169

169170
forM_ vpiSignals $ onAllSignalTypes $ \case
170-
IOInput{} -> return ()
171171
TBSignal{..} -> mapM_ (assignModuleInputs vpiInstance) signalDeps
172+
_ -> return ()
173+
172174

173175
let ?state = ?state { vpiClock = complement vpiClock
174176
, vpiInit = False
@@ -207,7 +209,6 @@ readOutputs = do
207209
-- putStrLn $ "readOutputs " <> show time
208210

209211
forM_ vpiSignals $ onAllSignalTypes $ \case
210-
IOInput{} -> return ()
211212
TBSignal{..} -> case vpiInstance of
212213
Nothing -> error "Cannot read from module"
213214
Just VPIInstance{..} ->
@@ -216,6 +217,7 @@ readOutputs = do
216217
Just upd -> liftIO $ upd $ unpack $ resize v
217218
Nothing -> error "No signal update"
218219
_ -> error "Unexpected return format"
220+
_ -> return ()
219221

220222
-- print the watched signals
221223
i <- liftIO $ readIORef vpiStepRef
@@ -224,8 +226,9 @@ readOutputs = do
224226
case signalPrint s of
225227
Nothing -> return ()
226228
Just toStr -> putStrLn . (<> toStr v) $ case s of
227-
IOInput{} -> "I "
228-
TBSignal{} -> "O "
229+
IOInput{} -> "I "
230+
Generator{} -> "I "
231+
TBSignal{} -> "O "
229232

230233
-- proceed time for all instances not running trough Clash-FFI
231234
liftIO $ modifyIORef vpiStepRef (+ 1)
@@ -260,7 +263,6 @@ vpiInst ::
260263
(?signalFromID :: ID 'FINAL () -> SomeSignal 'FINAL, KnownDomain dom, BitPack a, Typeable b) =>
261264
Module -> TBSignal 'FINAL dom a -> SimCont b (TBSignal 'FINAL dom a)
262265
vpiInst vpiModule = \case
263-
IOInput{} -> error "Unfiltered IOInput"
264266
tbs@TBSignal{..} -> do
265267
ports <- modulePorts vpiModule
266268
dirs <- mapM direction ports
@@ -292,6 +294,7 @@ vpiInst vpiModule = \case
292294
_ -> error "TODO: later / "
293295

294296
return tbs { vpiInstance = Just VPIInstance{..} }
297+
_ -> error "Unfiltered TBS"
295298

296299
where
297300
isInput = \case

0 commit comments

Comments
 (0)